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