omnibox_popup_contents_view.cc revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/search/search.h"
87d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "chrome/browser/themes/theme_properties.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/omnibox/omnibox_view.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/omnibox/omnibox_result_view.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/omnibox/touch_omnibox_popup_contents_view.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "grit/ui_resources.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/theme_provider.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/path.h"
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ui/views/controls/image_view.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h"
207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "ui/views/window/non_client_view.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(USE_AURA)
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/corewm/window_animations.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// This is the number of pixels in the border image used to draw the bottom
297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// border + drop shadow interior to the "visual" border. We lay out assuming
307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// that this many pixels inside the border is "in the popup."
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const SkAlpha kGlassPopupAlpha = 240;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const SkAlpha kOpaquePopupAlpha = 255;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// This is the number of pixels in the border image interior to the actual
35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// border.
36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const int kBorderInterior = 6;
37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class OmniboxPopupContentsView::AutocompletePopupWidget
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : public views::Widget,
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      public base::SupportsWeakPtr<AutocompletePopupWidget> {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
4458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  AutocompletePopupWidget() {}
4558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  virtual ~AutocompletePopupWidget() {}
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(AutocompletePopupWidget);
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OmniboxPopupContentsView, public:
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OmniboxPopupView* OmniboxPopupContentsView::Create(
55a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const gfx::FontList& font_list,
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OmniboxView* omnibox_view,
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OmniboxEditModel* edit_model,
58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    LocationBarView* location_bar_view) {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OmniboxPopupContentsView* view = NULL;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ui::GetDisplayLayout() == ui::LAYOUT_TOUCH) {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view = new TouchOmniboxPopupContentsView(
62a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        font_list, omnibox_view, edit_model, location_bar_view);
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view = new OmniboxPopupContentsView(
65a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        font_list, omnibox_view, edit_model, location_bar_view);
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  view->Init();
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return view;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OmniboxPopupContentsView::OmniboxPopupContentsView(
73a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const gfx::FontList& font_list,
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OmniboxView* omnibox_view,
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OmniboxEditModel* edit_model,
76868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    LocationBarView* location_bar_view)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : model_(new OmniboxPopupModel(this, edit_model)),
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      omnibox_view_(omnibox_view),
79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      location_bar_view_(location_bar_view),
80a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      font_list_(font_list),
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ignore_mouse_drag_(false),
82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      size_animation_(this),
83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      left_margin_(0),
84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      right_margin_(0),
8558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      outside_vertical_padding_(0),
8658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      in_popup_init_(false) {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The contents is owned by the LocationBarView.
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  set_owned_by_client();
89868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  ui::ThemeProvider* theme = location_bar_view_->GetThemeProvider();
91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  bottom_shadow_ = theme->GetImageSkiaNamed(IDR_BUBBLE_B);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupContentsView::Init() {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This can't be done in the constructor as at that point we aren't
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // necessarily our final class yet, and we may have subclasses
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // overriding CreateResultView.
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < AutocompleteResult::kMaxMatches; ++i) {
99a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    OmniboxResultView* result_view = CreateResultView(this, i, font_list_);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result_view->SetVisible(false);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddChildViewAt(result_view, static_cast<int>(i));
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OmniboxPopupContentsView::~OmniboxPopupContentsView() {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't need to do anything with |popup_| here.  The OS either has already
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // closed the window, in which case it's been deleted, or it will soon, in
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // which case there's nothing we need to do.
10958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  CHECK(!in_popup_init_);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Rect OmniboxPopupContentsView::GetPopupBounds() const {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!size_animation_.is_animating())
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return target_bounds_;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect current_frame_bounds = start_bounds_;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int total_height_delta = target_bounds_.height() - start_bounds_.height();
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Round |current_height_delta| instead of truncating so we won't leave single
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // white pixels at the bottom of the popup as long when animating very small
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // height differences.
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int current_height_delta = static_cast<int>(
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      size_animation_.GetCurrentValue() * total_height_delta - 0.5);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  current_frame_bounds.set_height(
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      current_frame_bounds.height() + current_height_delta);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return current_frame_bounds;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupContentsView::LayoutChildren() {
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect contents_rect = GetContentsBounds();
130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  contents_rect.Inset(left_margin_,
1327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                      views::NonClientFrameView::kClientEdgeThickness +
1337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                          outside_vertical_padding_,
1347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                      right_margin_, outside_vertical_padding_);
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int top = contents_rect.y();
136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (size_t i = 0; i < AutocompleteResult::kMaxMatches; ++i) {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    View* v = child_at(i);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (v->visible()) {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      v->SetBounds(contents_rect.x(), top, contents_rect.width(),
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   v->GetPreferredSize().height());
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      top = v->bounds().bottom();
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OmniboxPopupContentsView, OmniboxPopupView overrides:
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool OmniboxPopupContentsView::IsOpen() const {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return popup_ != NULL;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupContentsView::InvalidateLine(size_t line) {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OmniboxResultView* result = result_view_at(line);
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result->Invalidate();
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (HasMatchAt(line) && GetMatchAtIndex(line).associated_keyword.get()) {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->ShowKeyword(IsSelectedIndex(line) &&
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        model_->selected_line_state() == OmniboxPopupModel::KEYWORD);
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupContentsView::UpdatePopupAppearance() {
164ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  const size_t hidden_matches = model_->result().ShouldHideTopMatch() ? 1 : 0;
165ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (model_->result().size() <= hidden_matches ||
166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      omnibox_view_->IsImeShowingPopup()) {
167868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // No matches or the IME is showing a popup window which may overlap
168868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // the omnibox popup window.  Close any existing popup.
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (popup_ != NULL) {
17058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      CHECK(!in_popup_init_);
17158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      size_animation_.Stop();
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // NOTE: Do NOT use CloseNow() here, as we may be deep in a callstack
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // triggered by the popup receiving a message (e.g. LBUTTONUP), and
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // destroying the popup would cause us to read garbage when we unwind back
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // to that level.
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      popup_->Close();  // This will eventually delete the popup.
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      popup_.reset();
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Update the match cached by each row, in the process of doing so make sure
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we have enough row views.
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const size_t result_size = model_->result().size();
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < result_size; ++i) {
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OmniboxResultView* view = result_view_at(i);
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    view->SetMatch(GetMatchAtIndex(i));
190ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    view->SetVisible(i >= hidden_matches);
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
192868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (size_t i = result_size; i < AutocompleteResult::kMaxMatches; ++i)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    child_at(i)->SetVisible(false);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  gfx::Point top_left_screen_coord;
196868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  int width;
197868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  location_bar_view_->GetOmniboxPopupPositioningInfo(
198868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      &top_left_screen_coord, &width, &left_margin_, &right_margin_);
199868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  gfx::Rect new_target_bounds(top_left_screen_coord,
200868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                              gfx::Size(width, CalculatePopupHeight()));
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we're animating and our target height changes, reset the animation.
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: If we just reset blindly on _every_ update, then when the user types
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // rapidly we could get "stuck" trying repeatedly to animate shrinking by the
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // last few pixels to get to one visible result.
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (new_target_bounds.height() != target_bounds_.height())
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_animation_.Reset();
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  target_bounds_ = new_target_bounds;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (popup_ == NULL) {
211868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    gfx::NativeView popup_parent =
212868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        location_bar_view_->GetWidget()->GetNativeView();
213868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the popup is currently closed, we need to create it.
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    popup_ = (new AutocompletePopupWidget)->AsWeakPtr();
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    params.can_activate = false;
218eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
219868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    params.parent = popup_parent;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    params.bounds = GetPopupBounds();
221868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    params.context = popup_parent;
22258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    in_popup_init_ = true;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    popup_->Init(params);
22458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    in_popup_init_ = false;
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(USE_AURA)
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    views::corewm::SetWindowVisibilityAnimationType(
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        popup_->GetNativeView(),
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        views::corewm::WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No animation for autocomplete popup appearance.
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    views::corewm::SetWindowVisibilityAnimationTransition(
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        popup_->GetNativeView(), views::corewm::ANIMATE_HIDE);
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    popup_->SetContentsView(this);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    popup_->StackAbove(omnibox_view_->GetRelativeWindowForPopup());
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!popup_.get()) {
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // For some IMEs GetRelativeWindowForPopup triggers the omnibox to lose
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // focus, thereby closing (and destroying) the popup.
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(sky): this won't be needed once we close the omnibox on input
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // window showing.
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    popup_->Show();
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Animate the popup shrinking, but don't animate growing larger since that
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // would make the popup feel less responsive.
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    start_bounds_ = GetWidget()->GetWindowBoundsInScreen();
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (target_bounds_.height() < start_bounds_.height())
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      size_animation_.Show();
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      start_bounds_ = target_bounds_;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    popup_->SetBounds(GetPopupBounds());
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
254424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  Layout();
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Rect OmniboxPopupContentsView::GetTargetBounds() {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return target_bounds_;
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupContentsView::PaintUpdatesNow() {
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(beng): remove this from the interface.
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupContentsView::OnDragCanceled() {
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ignore_mouse_drag_ = true;
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OmniboxPopupContentsView, OmniboxResultViewModel implementation:
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool OmniboxPopupContentsView::IsSelectedIndex(size_t index) const {
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return index == model_->selected_line();
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool OmniboxPopupContentsView::IsHoveredIndex(size_t index) const {
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return index == model_->hovered_line();
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Image OmniboxPopupContentsView::GetIconIfExtensionMatch(
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t index) const {
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!HasMatchAt(index))
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return gfx::Image();
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return model_->GetIconIfExtensionMatch(GetMatchAtIndex(index));
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OmniboxPopupContentsView, AnimationDelegate implementation:
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupContentsView::AnimationProgressed(
291d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const gfx::Animation* animation) {
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We should only be running the animation when the popup is already visible.
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(popup_ != NULL);
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  popup_->SetBounds(GetPopupBounds());
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OmniboxPopupContentsView, views::View overrides:
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupContentsView::Layout() {
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Size our children to the available content area.
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LayoutChildren();
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We need to manually schedule a paint here since we are a layered window and
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // won't implicitly require painting until we ask for one.
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SchedulePaint();
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)views::View* OmniboxPopupContentsView::GetEventHandlerForPoint(
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Point& point) {
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return this;
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
314c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)views::View* OmniboxPopupContentsView::GetTooltipHandlerForPoint(
315c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const gfx::Point& point) {
316c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return NULL;
317c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
318c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool OmniboxPopupContentsView::OnMousePressed(
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ui::MouseEvent& event) {
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ignore_mouse_drag_ = false;  // See comment on |ignore_mouse_drag_| in header.
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (event.IsLeftMouseButton() || event.IsMiddleMouseButton())
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateLineEvent(event, event.IsLeftMouseButton());
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool OmniboxPopupContentsView::OnMouseDragged(
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ui::MouseEvent& event) {
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (event.IsLeftMouseButton() || event.IsMiddleMouseButton())
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateLineEvent(event, !ignore_mouse_drag_ && event.IsLeftMouseButton());
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupContentsView::OnMouseReleased(
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ui::MouseEvent& event) {
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ignore_mouse_drag_) {
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnMouseCaptureLost();
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (event.IsOnlyMiddleMouseButton() || event.IsOnlyLeftMouseButton()) {
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OpenSelectedLine(event, event.IsOnlyLeftMouseButton() ? CURRENT_TAB :
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                            NEW_BACKGROUND_TAB);
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupContentsView::OnMouseCaptureLost() {
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ignore_mouse_drag_ = false;
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupContentsView::OnMouseMoved(
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ui::MouseEvent& event) {
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_->SetHoveredLine(GetIndexForPoint(event.location()));
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupContentsView::OnMouseEntered(
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ui::MouseEvent& event) {
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_->SetHoveredLine(GetIndexForPoint(event.location()));
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupContentsView::OnMouseExited(
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ui::MouseEvent& event) {
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_->SetHoveredLine(OmniboxPopupModel::kNoMatch);
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OmniboxPopupContentsView::OnGestureEvent(ui::GestureEvent* event) {
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (event->type()) {
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ui::ET_GESTURE_TAP_DOWN:
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ui::ET_GESTURE_SCROLL_BEGIN:
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ui::ET_GESTURE_SCROLL_UPDATE:
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UpdateLineEvent(*event, true);
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ui::ET_GESTURE_TAP:
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ui::ET_GESTURE_SCROLL_END:
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      OpenSelectedLine(*event, CURRENT_TAB);
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  event->SetHandled();
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OmniboxPopupContentsView, protected:
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupContentsView::PaintResultViews(gfx::Canvas* canvas) {
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  canvas->DrawColor(result_view_at(0)->GetColor(
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      OmniboxResultView::NORMAL, OmniboxResultView::BACKGROUND));
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  View::PaintChildren(canvas);
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int OmniboxPopupContentsView::CalculatePopupHeight() {
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GE(static_cast<size_t>(child_count()), model_->result().size());
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int popup_height = 0;
395ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  for (size_t i = model_->result().ShouldHideTopMatch() ? 1 : 0;
396ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch       i < model_->result().size(); ++i)
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    popup_height += child_at(i)->GetPreferredSize().height();
398868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
399868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Add enough space on the top and bottom so it looks like there is the same
400868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // amount of space between the text and the popup border as there is in the
401868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // interior between each row of text.
402868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  //
403868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Discovering the exact amount of leading and padding around the font is
404868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // a bit tricky and platform-specific, but this computation seems to work in
405868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // practice.
406868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  OmniboxResultView* result_view = result_view_at(0);
407868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  outside_vertical_padding_ =
408868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      (result_view->GetPreferredSize().height() -
409868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       result_view->GetTextHeight());
410868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
4117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return popup_height +
4127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)         views::NonClientFrameView::kClientEdgeThickness +  // Top border.
4137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)         outside_vertical_padding_ * 2 +                    // Padding.
4147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)         bottom_shadow_->height() - kBorderInterior;        // Bottom border.
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OmniboxResultView* OmniboxPopupContentsView::CreateResultView(
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OmniboxResultViewModel* model,
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int model_index,
420a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const gfx::FontList& font_list) {
421a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return new OmniboxResultView(model, model_index, location_bar_view_,
422a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                               font_list);
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OmniboxPopupContentsView, views::View overrides, protected:
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupContentsView::OnPaint(gfx::Canvas* canvas) {
429868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  gfx::Rect contents_bounds = GetContentsBounds();
430868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  contents_bounds.set_height(
431868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      contents_bounds.height() - bottom_shadow_->height() + kBorderInterior);
432868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Path path;
434868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  MakeContentsPath(&path, contents_bounds);
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  canvas->Save();
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  canvas->sk_canvas()->clipPath(path,
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                SkRegion::kIntersect_Op,
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                true /* doAntialias */);
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PaintResultViews(canvas);
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  canvas->Restore();
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Top border.
4437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  canvas->FillRect(
4447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      gfx::Rect(0, 0, width(), views::NonClientFrameView::kClientEdgeThickness),
4457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      ThemeProperties::GetDefaultColor(
4467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          ThemeProperties::COLOR_TOOLBAR_SEPARATOR));
4477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
4487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Bottom border.
449868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  canvas->TileImageInt(*bottom_shadow_, 0, height() - bottom_shadow_->height(),
450868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                       width(), bottom_shadow_->height());
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupContentsView::PaintChildren(gfx::Canvas* canvas) {
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We paint our children inside OnPaint().
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OmniboxPopupContentsView, private:
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool OmniboxPopupContentsView::HasMatchAt(size_t index) const {
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return index < model_->result().size();
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const AutocompleteMatch& OmniboxPopupContentsView::GetMatchAtIndex(
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t index) const {
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return model_->result().match_at(index);
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupContentsView::MakeContentsPath(
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Path* path,
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Rect& bounding_rect) {
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SkRect rect;
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rect.set(SkIntToScalar(bounding_rect.x()),
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           SkIntToScalar(bounding_rect.y()),
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           SkIntToScalar(bounding_rect.right()),
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           SkIntToScalar(bounding_rect.bottom()));
477868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  path->addRect(rect);
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t OmniboxPopupContentsView::GetIndexForPoint(
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Point& point) {
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!HitTestPoint(point))
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return OmniboxPopupModel::kNoMatch;
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nb_match = model_->result().size();
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(nb_match <= child_count());
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < nb_match; ++i) {
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::View* child = child_at(i);
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Point point_in_child_coords(point);
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    View::ConvertPointToTarget(this, child, &point_in_child_coords);
491ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    if (child->visible() && child->HitTestPoint(point_in_child_coords))
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return i;
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return OmniboxPopupModel::kNoMatch;
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupContentsView::UpdateLineEvent(
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ui::LocatedEvent& event,
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool should_set_selected_line) {
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t index = GetIndexForPoint(event.location());
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_->SetHoveredLine(index);
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (HasMatchAt(index) && should_set_selected_line)
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model_->SetSelectedLine(index, false, false);
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxPopupContentsView::OpenSelectedLine(
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ui::LocatedEvent& event,
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WindowOpenDisposition disposition) {
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t index = GetIndexForPoint(event.location());
510868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!HasMatchAt(index))
511868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
512868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
513868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // OpenMatch() may close the popup, which will clear the result set and, by
514868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // extension, |match| and its contents.  So copy the relevant match out to
515868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // make sure it stays alive until the call completes.
516868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  AutocompleteMatch match = model_->result().match_at(index);
517868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  omnibox_view_->OpenMatch(match, disposition, GURL(), index);
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OmniboxResultView* OmniboxPopupContentsView::result_view_at(size_t i) {
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return static_cast<OmniboxResultView*>(child_at(static_cast<int>(i)));
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
523