| OLD | NEW | 
 | (Empty) | 
|    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/autocomplete/autocomplete_popup_contents_view.
     h" |  | 
|    6  |  | 
|    7 #if defined(OS_WIN) |  | 
|    8 #include <commctrl.h> |  | 
|    9 #include <dwmapi.h> |  | 
|   10 #include <objidl.h> |  | 
|   11 #endif |  | 
|   12  |  | 
|   13 #include "base/compiler_specific.h" |  | 
|   14 #include "base/utf_string_conversions.h" |  | 
|   15 #include "chrome/browser/autocomplete/autocomplete_popup_model.h" |  | 
|   16 #include "chrome/browser/profiles/profile.h" |  | 
|   17 #include "chrome/browser/themes/theme_service.h" |  | 
|   18 #include "chrome/browser/ui/omnibox/omnibox_view.h" |  | 
|   19 #include "chrome/browser/ui/views/autocomplete/autocomplete_result_view.h" |  | 
|   20 #include "chrome/browser/ui/views/location_bar/location_bar_view.h" |  | 
|   21 #include "chrome/browser/ui/views/autocomplete/touch_autocomplete_popup_contents
     _view.h" |  | 
|   22 #include "grit/chromium_strings.h" |  | 
|   23 #include "grit/generated_resources.h" |  | 
|   24 #include "grit/theme_resources.h" |  | 
|   25 #include "third_party/skia/include/core/SkShader.h" |  | 
|   26 #include "ui/base/l10n/l10n_util.h" |  | 
|   27 #include "ui/base/layout.h" |  | 
|   28 #include "ui/base/resource/resource_bundle.h" |  | 
|   29 #include "ui/base/theme_provider.h" |  | 
|   30 #include "ui/gfx/canvas.h" |  | 
|   31 #include "ui/gfx/insets.h" |  | 
|   32 #include "ui/gfx/path.h" |  | 
|   33 #include "ui/views/bubble/bubble_border.h" |  | 
|   34 #include "ui/views/controls/button/text_button.h" |  | 
|   35 #include "ui/views/controls/label.h" |  | 
|   36 #include "ui/views/layout/grid_layout.h" |  | 
|   37 #include "ui/views/layout/layout_constants.h" |  | 
|   38 #include "ui/views/painter.h" |  | 
|   39 #include "ui/views/widget/widget.h" |  | 
|   40 #include "unicode/ubidi.h" |  | 
|   41  |  | 
|   42 #if defined(OS_WIN) |  | 
|   43 #include "base/win/scoped_gdi_object.h" |  | 
|   44 #if !defined(USE_AURA) |  | 
|   45 #include "ui/views/widget/native_widget_win.h" |  | 
|   46 #endif |  | 
|   47 #endif |  | 
|   48 #if defined(USE_ASH) |  | 
|   49 #include "ash/wm/window_animations.h" |  | 
|   50 #endif |  | 
|   51  |  | 
|   52 namespace { |  | 
|   53  |  | 
|   54 const SkAlpha kGlassPopupAlpha = 240; |  | 
|   55 const SkAlpha kOpaquePopupAlpha = 255; |  | 
|   56  |  | 
|   57 // The size delta between the font used for the edit and the result rows. Passed |  | 
|   58 // to gfx::Font::DeriveFont. |  | 
|   59 #if defined(OS_CHROMEOS) |  | 
|   60 // Don't adjust the size on Chrome OS (http://crbug.com/61433). |  | 
|   61 const int kEditFontAdjust = 0; |  | 
|   62 #else |  | 
|   63 const int kEditFontAdjust = -1; |  | 
|   64 #endif |  | 
|   65  |  | 
|   66 }  // namespace |  | 
|   67  |  | 
|   68 class AutocompletePopupContentsView::AutocompletePopupWidget |  | 
|   69     : public views::Widget, |  | 
|   70       public base::SupportsWeakPtr<AutocompletePopupWidget> { |  | 
|   71  public: |  | 
|   72   AutocompletePopupWidget() {} |  | 
|   73   virtual ~AutocompletePopupWidget() {} |  | 
|   74  |  | 
|   75  private: |  | 
|   76   DISALLOW_COPY_AND_ASSIGN(AutocompletePopupWidget); |  | 
|   77 }; |  | 
|   78  |  | 
|   79 //////////////////////////////////////////////////////////////////////////////// |  | 
|   80 // AutocompletePopupContentsView, public: |  | 
|   81  |  | 
|   82 AutocompletePopupContentsView* |  | 
|   83     AutocompletePopupContentsView::CreateForEnvironment( |  | 
|   84         const gfx::Font& font, |  | 
|   85         OmniboxView* omnibox_view, |  | 
|   86         AutocompleteEditModel* edit_model, |  | 
|   87         views::View* location_bar) { |  | 
|   88   AutocompletePopupContentsView* view = NULL; |  | 
|   89   if (ui::GetDisplayLayout() == ui::LAYOUT_TOUCH) { |  | 
|   90     view = new TouchAutocompletePopupContentsView( |  | 
|   91         font, omnibox_view, edit_model, location_bar); |  | 
|   92   } else { |  | 
|   93     view = new AutocompletePopupContentsView( |  | 
|   94         font, omnibox_view, edit_model, location_bar); |  | 
|   95   } |  | 
|   96  |  | 
|   97   view->Init(); |  | 
|   98   return view; |  | 
|   99 } |  | 
|  100  |  | 
|  101 AutocompletePopupContentsView::AutocompletePopupContentsView( |  | 
|  102     const gfx::Font& font, |  | 
|  103     OmniboxView* omnibox_view, |  | 
|  104     AutocompleteEditModel* edit_model, |  | 
|  105     views::View* location_bar) |  | 
|  106     : model_(new AutocompletePopupModel(this, edit_model)), |  | 
|  107       omnibox_view_(omnibox_view), |  | 
|  108       profile_(edit_model->profile()), |  | 
|  109       location_bar_(location_bar), |  | 
|  110       result_font_(font.DeriveFont(kEditFontAdjust)), |  | 
|  111       result_bold_font_(result_font_.DeriveFont(0, gfx::Font::BOLD)), |  | 
|  112       ignore_mouse_drag_(false), |  | 
|  113       ALLOW_THIS_IN_INITIALIZER_LIST(size_animation_(this)) { |  | 
|  114   // The following little dance is required because set_border() requires a |  | 
|  115   // pointer to a non-const object. |  | 
|  116   views::BubbleBorder* bubble_border = |  | 
|  117       new views::BubbleBorder(views::BubbleBorder::NONE, |  | 
|  118                               views::BubbleBorder::NO_SHADOW); |  | 
|  119   bubble_border_ = bubble_border; |  | 
|  120   set_border(bubble_border); |  | 
|  121   // The contents is owned by the LocationBarView. |  | 
|  122   set_owned_by_client(); |  | 
|  123 } |  | 
|  124  |  | 
|  125 void AutocompletePopupContentsView::Init() { |  | 
|  126   // This can't be done in the constructor as at that point we aren't |  | 
|  127   // necessarily our final class yet, and we may have subclasses |  | 
|  128   // overriding CreateResultView. |  | 
|  129   for (size_t i = 0; i < AutocompleteResult::kMaxMatches; ++i) { |  | 
|  130     AutocompleteResultView* result_view = |  | 
|  131         CreateResultView(this, i, result_font_, result_bold_font_); |  | 
|  132     result_view->SetVisible(false); |  | 
|  133     AddChildViewAt(result_view, static_cast<int>(i)); |  | 
|  134   } |  | 
|  135 } |  | 
|  136  |  | 
|  137 AutocompletePopupContentsView::~AutocompletePopupContentsView() { |  | 
|  138   // We don't need to do anything with |popup_| here.  The OS either has already |  | 
|  139   // closed the window, in which case it's been deleted, or it will soon, in |  | 
|  140   // which case there's nothing we need to do. |  | 
|  141 } |  | 
|  142  |  | 
|  143 gfx::Rect AutocompletePopupContentsView::GetPopupBounds() const { |  | 
|  144   if (!size_animation_.is_animating()) |  | 
|  145     return target_bounds_; |  | 
|  146  |  | 
|  147   gfx::Rect current_frame_bounds = start_bounds_; |  | 
|  148   int total_height_delta = target_bounds_.height() - start_bounds_.height(); |  | 
|  149   // Round |current_height_delta| instead of truncating so we won't leave single |  | 
|  150   // white pixels at the bottom of the popup as long when animating very small |  | 
|  151   // height differences. |  | 
|  152   int current_height_delta = static_cast<int>( |  | 
|  153       size_animation_.GetCurrentValue() * total_height_delta - 0.5); |  | 
|  154   current_frame_bounds.set_height( |  | 
|  155       current_frame_bounds.height() + current_height_delta); |  | 
|  156   return current_frame_bounds; |  | 
|  157 } |  | 
|  158  |  | 
|  159 void AutocompletePopupContentsView::LayoutChildren() { |  | 
|  160   gfx::Rect contents_rect = GetContentsBounds(); |  | 
|  161   int top = contents_rect.y(); |  | 
|  162   for (int i = 0; i < child_count(); ++i) { |  | 
|  163     View* v = child_at(i); |  | 
|  164     if (v->visible()) { |  | 
|  165       v->SetBounds(contents_rect.x(), top, contents_rect.width(), |  | 
|  166                    v->GetPreferredSize().height()); |  | 
|  167       top = v->bounds().bottom(); |  | 
|  168     } |  | 
|  169   } |  | 
|  170 } |  | 
|  171  |  | 
|  172 //////////////////////////////////////////////////////////////////////////////// |  | 
|  173 // AutocompletePopupContentsView, AutocompletePopupView overrides: |  | 
|  174  |  | 
|  175 bool AutocompletePopupContentsView::IsOpen() const { |  | 
|  176   return (popup_ != NULL); |  | 
|  177 } |  | 
|  178  |  | 
|  179 void AutocompletePopupContentsView::InvalidateLine(size_t line) { |  | 
|  180   AutocompleteResultView* result = static_cast<AutocompleteResultView*>( |  | 
|  181       child_at(static_cast<int>(line))); |  | 
|  182   result->Invalidate(); |  | 
|  183  |  | 
|  184   if (HasMatchAt(line) && GetMatchAtIndex(line).associated_keyword.get()) { |  | 
|  185     result->ShowKeyword(IsSelectedIndex(line) && |  | 
|  186         model_->selected_line_state() == AutocompletePopupModel::KEYWORD); |  | 
|  187   } |  | 
|  188 } |  | 
|  189  |  | 
|  190 void AutocompletePopupContentsView::UpdatePopupAppearance() { |  | 
|  191   if (model_->result().empty()) { |  | 
|  192     // No matches, close any existing popup. |  | 
|  193     if (popup_ != NULL) { |  | 
|  194       size_animation_.Stop(); |  | 
|  195  |  | 
|  196       // NOTE: Do NOT use CloseNow() here, as we may be deep in a callstack |  | 
|  197       // triggered by the popup receiving a message (e.g. LBUTTONUP), and |  | 
|  198       // destroying the popup would cause us to read garbage when we unwind back |  | 
|  199       // to that level. |  | 
|  200       popup_->Close();  // This will eventually delete the popup. |  | 
|  201       popup_.reset(); |  | 
|  202     } |  | 
|  203     return; |  | 
|  204   } |  | 
|  205  |  | 
|  206   // Update the match cached by each row, in the process of doing so make sure |  | 
|  207   // we have enough row views. |  | 
|  208   size_t child_rv_count = child_count(); |  | 
|  209   const size_t result_size = model_->result().size(); |  | 
|  210   for (size_t i = 0; i < result_size; ++i) { |  | 
|  211     AutocompleteResultView* view = static_cast<AutocompleteResultView*>( |  | 
|  212         child_at(i)); |  | 
|  213     view->SetMatch(GetMatchAtIndex(i)); |  | 
|  214     view->SetVisible(true); |  | 
|  215   } |  | 
|  216   for (size_t i = result_size; i < child_rv_count; ++i) |  | 
|  217     child_at(i)->SetVisible(false); |  | 
|  218  |  | 
|  219   gfx::Rect new_target_bounds = CalculateTargetBounds(CalculatePopupHeight()); |  | 
|  220  |  | 
|  221   // If we're animating and our target height changes, reset the animation. |  | 
|  222   // NOTE: If we just reset blindly on _every_ update, then when the user types |  | 
|  223   // rapidly we could get "stuck" trying repeatedly to animate shrinking by the |  | 
|  224   // last few pixels to get to one visible result. |  | 
|  225   if (new_target_bounds.height() != target_bounds_.height()) |  | 
|  226     size_animation_.Reset(); |  | 
|  227   target_bounds_ = new_target_bounds; |  | 
|  228  |  | 
|  229   if (popup_ == NULL) { |  | 
|  230     // If the popup is currently closed, we need to create it. |  | 
|  231     popup_ = (new AutocompletePopupWidget)->AsWeakPtr(); |  | 
|  232     views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); |  | 
|  233     params.can_activate = false; |  | 
|  234     params.transparent = true; |  | 
|  235     params.parent_widget = location_bar_->GetWidget(); |  | 
|  236     params.bounds = GetPopupBounds(); |  | 
|  237     popup_->Init(params); |  | 
|  238 #if defined(USE_ASH) |  | 
|  239     ash::SetWindowVisibilityAnimationType( |  | 
|  240         popup_->GetNativeView(), |  | 
|  241         ash::WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL); |  | 
|  242     // No animation for autocomplete popup appearance.  see crbug.com/124104 |  | 
|  243     ash::SetWindowVisibilityAnimationTransition( |  | 
|  244         popup_->GetNativeView(), ash::ANIMATE_HIDE); |  | 
|  245 #endif |  | 
|  246     popup_->SetContentsView(this); |  | 
|  247     popup_->StackAbove(omnibox_view_->GetRelativeWindowForPopup()); |  | 
|  248     if (!popup_.get()) { |  | 
|  249       // For some IMEs GetRelativeWindowForPopup triggers the omnibox to lose |  | 
|  250       // focus, thereby closing (and destroying) the popup. |  | 
|  251       // TODO(sky): this won't be needed once we close the omnibox on input |  | 
|  252       // window showing. |  | 
|  253       return; |  | 
|  254     } |  | 
|  255     popup_->Show(); |  | 
|  256   } else { |  | 
|  257     // Animate the popup shrinking, but don't animate growing larger since that |  | 
|  258     // would make the popup feel less responsive. |  | 
|  259     start_bounds_ = GetWidget()->GetWindowScreenBounds(); |  | 
|  260     if (target_bounds_.height() < start_bounds_.height()) |  | 
|  261       size_animation_.Show(); |  | 
|  262     else |  | 
|  263       start_bounds_ = target_bounds_; |  | 
|  264     popup_->SetBounds(GetPopupBounds()); |  | 
|  265   } |  | 
|  266  |  | 
|  267   SchedulePaint(); |  | 
|  268 } |  | 
|  269  |  | 
|  270 gfx::Rect AutocompletePopupContentsView::GetTargetBounds() { |  | 
|  271   return target_bounds_; |  | 
|  272 } |  | 
|  273  |  | 
|  274 void AutocompletePopupContentsView::PaintUpdatesNow() { |  | 
|  275   // TODO(beng): remove this from the interface. |  | 
|  276 } |  | 
|  277  |  | 
|  278 void AutocompletePopupContentsView::OnDragCanceled() { |  | 
|  279   ignore_mouse_drag_ = true; |  | 
|  280 } |  | 
|  281  |  | 
|  282 //////////////////////////////////////////////////////////////////////////////// |  | 
|  283 // AutocompletePopupContentsView, AutocompleteResultViewModel implementation: |  | 
|  284  |  | 
|  285 bool AutocompletePopupContentsView::IsSelectedIndex(size_t index) const { |  | 
|  286   return index == model_->selected_line(); |  | 
|  287 } |  | 
|  288  |  | 
|  289 bool AutocompletePopupContentsView::IsHoveredIndex(size_t index) const { |  | 
|  290   return index == model_->hovered_line(); |  | 
|  291 } |  | 
|  292  |  | 
|  293 const SkBitmap* AutocompletePopupContentsView::GetIconIfExtensionMatch( |  | 
|  294     size_t index) const { |  | 
|  295   if (!HasMatchAt(index)) |  | 
|  296     return NULL; |  | 
|  297   return model_->GetIconIfExtensionMatch(GetMatchAtIndex(index)); |  | 
|  298 } |  | 
|  299  |  | 
|  300 //////////////////////////////////////////////////////////////////////////////// |  | 
|  301 // AutocompletePopupContentsView, AnimationDelegate implementation: |  | 
|  302  |  | 
|  303 void AutocompletePopupContentsView::AnimationProgressed( |  | 
|  304     const ui::Animation* animation) { |  | 
|  305   // We should only be running the animation when the popup is already visible. |  | 
|  306   DCHECK(popup_ != NULL); |  | 
|  307   popup_->SetBounds(GetPopupBounds()); |  | 
|  308 } |  | 
|  309  |  | 
|  310 //////////////////////////////////////////////////////////////////////////////// |  | 
|  311 // AutocompletePopupContentsView, views::View overrides: |  | 
|  312  |  | 
|  313 void AutocompletePopupContentsView::Layout() { |  | 
|  314   UpdateBlurRegion(); |  | 
|  315  |  | 
|  316   // Size our children to the available content area. |  | 
|  317   LayoutChildren(); |  | 
|  318  |  | 
|  319   // We need to manually schedule a paint here since we are a layered window and |  | 
|  320   // won't implicitly require painting until we ask for one. |  | 
|  321   SchedulePaint(); |  | 
|  322 } |  | 
|  323  |  | 
|  324 views::View* AutocompletePopupContentsView::GetEventHandlerForPoint( |  | 
|  325     const gfx::Point& point) { |  | 
|  326   return this; |  | 
|  327 } |  | 
|  328  |  | 
|  329 bool AutocompletePopupContentsView::OnMousePressed( |  | 
|  330     const views::MouseEvent& event) { |  | 
|  331   ignore_mouse_drag_ = false;  // See comment on |ignore_mouse_drag_| in header. |  | 
|  332   if (event.IsLeftMouseButton() || event.IsMiddleMouseButton()) |  | 
|  333     UpdateLineEvent(event, event.IsLeftMouseButton()); |  | 
|  334   return true; |  | 
|  335 } |  | 
|  336  |  | 
|  337 bool AutocompletePopupContentsView::OnMouseDragged( |  | 
|  338     const views::MouseEvent& event) { |  | 
|  339   if (event.IsLeftMouseButton() || event.IsMiddleMouseButton()) |  | 
|  340     UpdateLineEvent(event, !ignore_mouse_drag_ && event.IsLeftMouseButton()); |  | 
|  341   return true; |  | 
|  342 } |  | 
|  343  |  | 
|  344 void AutocompletePopupContentsView::OnMouseReleased( |  | 
|  345     const views::MouseEvent& event) { |  | 
|  346   if (ignore_mouse_drag_) { |  | 
|  347     OnMouseCaptureLost(); |  | 
|  348     return; |  | 
|  349   } |  | 
|  350  |  | 
|  351   if (event.IsOnlyMiddleMouseButton() || event.IsOnlyLeftMouseButton()) { |  | 
|  352     OpenSelectedLine(event, event.IsOnlyLeftMouseButton() ? CURRENT_TAB : |  | 
|  353                                                             NEW_BACKGROUND_TAB); |  | 
|  354   } |  | 
|  355 } |  | 
|  356  |  | 
|  357 void AutocompletePopupContentsView::OnMouseCaptureLost() { |  | 
|  358   ignore_mouse_drag_ = false; |  | 
|  359 } |  | 
|  360  |  | 
|  361 void AutocompletePopupContentsView::OnMouseMoved( |  | 
|  362     const views::MouseEvent& event) { |  | 
|  363   model_->SetHoveredLine(GetIndexForPoint(event.location())); |  | 
|  364 } |  | 
|  365  |  | 
|  366 void AutocompletePopupContentsView::OnMouseEntered( |  | 
|  367     const views::MouseEvent& event) { |  | 
|  368   model_->SetHoveredLine(GetIndexForPoint(event.location())); |  | 
|  369 } |  | 
|  370  |  | 
|  371 void AutocompletePopupContentsView::OnMouseExited( |  | 
|  372     const views::MouseEvent& event) { |  | 
|  373   model_->SetHoveredLine(AutocompletePopupModel::kNoMatch); |  | 
|  374 } |  | 
|  375  |  | 
|  376 ui::GestureStatus AutocompletePopupContentsView::OnGestureEvent( |  | 
|  377     const views::GestureEvent& event) { |  | 
|  378   switch (event.type()) { |  | 
|  379     case ui::ET_GESTURE_TAP_DOWN: |  | 
|  380     case ui::ET_GESTURE_SCROLL_BEGIN: |  | 
|  381     case ui::ET_GESTURE_SCROLL_UPDATE: |  | 
|  382       UpdateLineEvent(event, true); |  | 
|  383       break; |  | 
|  384     case ui::ET_GESTURE_TAP: |  | 
|  385     case ui::ET_GESTURE_SCROLL_END: |  | 
|  386       OpenSelectedLine(event, CURRENT_TAB); |  | 
|  387       break; |  | 
|  388     default: |  | 
|  389       return ui::GESTURE_STATUS_UNKNOWN; |  | 
|  390   } |  | 
|  391   return ui::GESTURE_STATUS_CONSUMED; |  | 
|  392 } |  | 
|  393  |  | 
|  394 //////////////////////////////////////////////////////////////////////////////// |  | 
|  395 // AutocompletePopupContentsView, protected: |  | 
|  396  |  | 
|  397 void AutocompletePopupContentsView::PaintResultViews(gfx::Canvas* canvas) { |  | 
|  398   canvas->DrawColor(AutocompleteResultView::GetColor( |  | 
|  399       AutocompleteResultView::NORMAL, AutocompleteResultView::BACKGROUND)); |  | 
|  400   View::PaintChildren(canvas); |  | 
|  401 } |  | 
|  402  |  | 
|  403 int AutocompletePopupContentsView::CalculatePopupHeight() { |  | 
|  404   DCHECK_GE(static_cast<size_t>(child_count()), model_->result().size()); |  | 
|  405   int popup_height = 0; |  | 
|  406   for (size_t i = 0; i < model_->result().size(); ++i) |  | 
|  407     popup_height += child_at(i)->GetPreferredSize().height(); |  | 
|  408   return popup_height; |  | 
|  409 } |  | 
|  410  |  | 
|  411 AutocompleteResultView* AutocompletePopupContentsView::CreateResultView( |  | 
|  412     AutocompleteResultViewModel* model, |  | 
|  413     int model_index, |  | 
|  414     const gfx::Font& font, |  | 
|  415     const gfx::Font& bold_font) { |  | 
|  416   return new AutocompleteResultView(model, model_index, font, bold_font); |  | 
|  417 } |  | 
|  418  |  | 
|  419 //////////////////////////////////////////////////////////////////////////////// |  | 
|  420 // AutocompletePopupContentsView, views::View overrides, protected: |  | 
|  421  |  | 
|  422 void AutocompletePopupContentsView::OnPaint(gfx::Canvas* canvas) { |  | 
|  423   gfx::Path path; |  | 
|  424   MakeContentsPath(&path, GetContentsBounds()); |  | 
|  425   canvas->Save(); |  | 
|  426   canvas->sk_canvas()->clipPath(path, |  | 
|  427                                 SkRegion::kIntersect_Op, |  | 
|  428                                 true /* doAntialias */); |  | 
|  429   PaintResultViews(canvas); |  | 
|  430  |  | 
|  431   // We want the contents background to be slightly transparent so we can see |  | 
|  432   // the blurry glass effect on DWM systems behind. We do this _after_ we paint |  | 
|  433   // the children since they paint text, and GDI will reset this alpha data if |  | 
|  434   // we paint text after this call. |  | 
|  435   MakeCanvasTransparent(canvas); |  | 
|  436   canvas->Restore(); |  | 
|  437  |  | 
|  438   // Now we paint the border, so it will be alpha-blended atop the contents. |  | 
|  439   // This looks slightly better in the corners than drawing the contents atop |  | 
|  440   // the border. |  | 
|  441   OnPaintBorder(canvas); |  | 
|  442 } |  | 
|  443  |  | 
|  444 void AutocompletePopupContentsView::PaintChildren(gfx::Canvas* canvas) { |  | 
|  445   // We paint our children inside OnPaint(). |  | 
|  446 } |  | 
|  447  |  | 
|  448 //////////////////////////////////////////////////////////////////////////////// |  | 
|  449 // AutocompletePopupContentsView, private: |  | 
|  450  |  | 
|  451 bool AutocompletePopupContentsView::HasMatchAt(size_t index) const { |  | 
|  452   return index < model_->result().size(); |  | 
|  453 } |  | 
|  454  |  | 
|  455 const AutocompleteMatch& AutocompletePopupContentsView::GetMatchAtIndex( |  | 
|  456     size_t index) const { |  | 
|  457   return model_->result().match_at(index); |  | 
|  458 } |  | 
|  459  |  | 
|  460 void AutocompletePopupContentsView::MakeContentsPath( |  | 
|  461     gfx::Path* path, |  | 
|  462     const gfx::Rect& bounding_rect) { |  | 
|  463   SkRect rect; |  | 
|  464   rect.set(SkIntToScalar(bounding_rect.x()), |  | 
|  465            SkIntToScalar(bounding_rect.y()), |  | 
|  466            SkIntToScalar(bounding_rect.right()), |  | 
|  467            SkIntToScalar(bounding_rect.bottom())); |  | 
|  468  |  | 
|  469   SkScalar radius = SkIntToScalar(views::BubbleBorder::GetCornerRadius()); |  | 
|  470   path->addRoundRect(rect, radius, radius); |  | 
|  471 } |  | 
|  472  |  | 
|  473 void AutocompletePopupContentsView::UpdateBlurRegion() { |  | 
|  474 #if defined(OS_WIN) && !defined(USE_AURA) |  | 
|  475   // We only support background blurring on Vista with Aero-Glass enabled. |  | 
|  476   if (!views::NativeWidgetWin::IsAeroGlassEnabled() || !GetWidget()) |  | 
|  477     return; |  | 
|  478  |  | 
|  479   // Provide a blurred background effect within the contents region of the |  | 
|  480   // popup. |  | 
|  481   DWM_BLURBEHIND bb = {0}; |  | 
|  482   bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; |  | 
|  483   bb.fEnable = true; |  | 
|  484  |  | 
|  485   // Translate the contents rect into widget coordinates, since that's what |  | 
|  486   // DwmEnableBlurBehindWindow expects a region in. |  | 
|  487   gfx::Rect contents_rect = ConvertRectToWidget(GetContentsBounds()); |  | 
|  488   gfx::Path contents_path; |  | 
|  489   MakeContentsPath(&contents_path, contents_rect); |  | 
|  490   base::win::ScopedGDIObject<HRGN> popup_region; |  | 
|  491   popup_region.Set(contents_path.CreateNativeRegion()); |  | 
|  492   bb.hRgnBlur = popup_region.Get(); |  | 
|  493   DwmEnableBlurBehindWindow(GetWidget()->GetNativeView(), &bb); |  | 
|  494 #endif |  | 
|  495 } |  | 
|  496  |  | 
|  497 void AutocompletePopupContentsView::MakeCanvasTransparent( |  | 
|  498     gfx::Canvas* canvas) { |  | 
|  499   // Allow the window blur effect to show through the popup background. |  | 
|  500   SkAlpha alpha = GetThemeProvider()->ShouldUseNativeFrame() ? |  | 
|  501       kGlassPopupAlpha : kOpaquePopupAlpha; |  | 
|  502   canvas->DrawColor(SkColorSetA( |  | 
|  503       AutocompleteResultView::GetColor(AutocompleteResultView::NORMAL, |  | 
|  504       AutocompleteResultView::BACKGROUND), alpha), SkXfermode::kDstIn_Mode); |  | 
|  505 } |  | 
|  506  |  | 
|  507 void AutocompletePopupContentsView::OpenIndex( |  | 
|  508     size_t index, |  | 
|  509     WindowOpenDisposition disposition) { |  | 
|  510   if (!HasMatchAt(index)) |  | 
|  511     return; |  | 
|  512  |  | 
|  513   // OpenMatch() may close the popup, which will clear the result set and, by |  | 
|  514   // extension, |match| and its contents.  So copy the relevant match out to |  | 
|  515   // make sure it stays alive until the call completes. |  | 
|  516   AutocompleteMatch match = model_->result().match_at(index); |  | 
|  517   omnibox_view_->OpenMatch(match, disposition, GURL(), index); |  | 
|  518 } |  | 
|  519  |  | 
|  520 size_t AutocompletePopupContentsView::GetIndexForPoint( |  | 
|  521     const gfx::Point& point) { |  | 
|  522   if (!HitTest(point)) |  | 
|  523     return AutocompletePopupModel::kNoMatch; |  | 
|  524  |  | 
|  525   int nb_match = model_->result().size(); |  | 
|  526   DCHECK(nb_match <= child_count()); |  | 
|  527   for (int i = 0; i < nb_match; ++i) { |  | 
|  528     views::View* child = child_at(i); |  | 
|  529     gfx::Point point_in_child_coords(point); |  | 
|  530     View::ConvertPointToView(this, child, &point_in_child_coords); |  | 
|  531     if (child->HitTest(point_in_child_coords)) |  | 
|  532       return i; |  | 
|  533   } |  | 
|  534   return AutocompletePopupModel::kNoMatch; |  | 
|  535 } |  | 
|  536  |  | 
|  537 gfx::Rect AutocompletePopupContentsView::CalculateTargetBounds(int h) { |  | 
|  538   gfx::Rect location_bar_bounds(location_bar_->GetContentsBounds()); |  | 
|  539   const views::Border* border = location_bar_->border(); |  | 
|  540   if (border) { |  | 
|  541     // Adjust for the border so that the bubble and location bar borders are |  | 
|  542     // aligned. |  | 
|  543     gfx::Insets insets; |  | 
|  544     border->GetInsets(&insets); |  | 
|  545     location_bar_bounds.Inset(insets.left(), 0, insets.right(), 0); |  | 
|  546   } else { |  | 
|  547     // The normal location bar is drawn using a background graphic that includes |  | 
|  548     // the border, so we inset by enough to make the edges line up, and the |  | 
|  549     // bubble appear at the same height as the Star bubble. |  | 
|  550     location_bar_bounds.Inset(LocationBarView::kNormalHorizontalEdgeThickness, |  | 
|  551                               0); |  | 
|  552   } |  | 
|  553   gfx::Point location_bar_origin(location_bar_bounds.origin()); |  | 
|  554   views::View::ConvertPointToScreen(location_bar_, &location_bar_origin); |  | 
|  555   location_bar_bounds.set_origin(location_bar_origin); |  | 
|  556   return bubble_border_->GetBounds( |  | 
|  557       location_bar_bounds, gfx::Size(location_bar_bounds.width(), h)); |  | 
|  558 } |  | 
|  559  |  | 
|  560 void AutocompletePopupContentsView::UpdateLineEvent( |  | 
|  561     const views::LocatedEvent& event, |  | 
|  562     bool should_set_selected_line) { |  | 
|  563   size_t index = GetIndexForPoint(event.location()); |  | 
|  564   model_->SetHoveredLine(index); |  | 
|  565   if (HasMatchAt(index) && should_set_selected_line) |  | 
|  566     model_->SetSelectedLine(index, false, false); |  | 
|  567 } |  | 
|  568  |  | 
|  569 void AutocompletePopupContentsView::OpenSelectedLine( |  | 
|  570     const views::LocatedEvent& event, |  | 
|  571     WindowOpenDisposition disposition) { |  | 
|  572   size_t index = GetIndexForPoint(event.location()); |  | 
|  573   OpenIndex(index, disposition); |  | 
|  574 } |  | 
| OLD | NEW |