| 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 | 
|---|