172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/views/dropdown_bar_host.h" 672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include <algorithm> 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/view_ids.h" 1021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/views/dropdown_bar_view.h" 1121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/views/frame/browser_view.h" 123f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "ui/base/animation/slide_animation.h" 1372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/keycodes/keyboard_codes.h" 1472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/path.h" 1572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/scrollbar_size.h" 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/focus/external_focus_tracker.h" 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/focus/view_storage.h" 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/widget/widget.h" 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 203f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#if defined(OS_WIN) 213f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/win/scoped_gdi_object.h" 223f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#elif defined(OS_LINUX) 2372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/gtk/scoped_handle_gtk.h" 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 263f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsennamespace { 273f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 283f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#if defined(OS_WIN) 293f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsentypedef base::win::ScopedRegion ScopedPlatformRegion; 303f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#elif defined(OS_LINUX) 3172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsentypedef ui::ScopedRegion ScopedPlatformRegion; 323f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#endif 333f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 343f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen} // namespace 353f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing gfx::Path; 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool DropdownBarHost::disable_animations_during_testing_ = false; 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// DropdownBarHost, public: 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDropdownBarHost::DropdownBarHost(BrowserView* browser_view) 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : browser_view_(browser_view), 46dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen view_(NULL), 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch animation_offset_(0), 48dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen focus_manager_(NULL), 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch esc_accel_target_registered_(false), 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch is_visible_(false) { 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DropdownBarHost::Init(DropdownBarView* view) { 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_ = view; 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Initialize the host. 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch host_.reset(CreateHost()); 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch host_->InitWithWidget(browser_view_->GetWidget(), gfx::Rect()); 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch host_->SetContentsView(view_); 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Start listening to focus changes, so we can register and unregister our 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // own handler for Escape. 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch focus_manager_ = 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::FocusManager::GetFocusManagerForNativeView(host_->GetNativeView()); 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (focus_manager_) { 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch focus_manager_->AddFocusChangeListener(this); 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // In some cases (see bug http://crbug.com/17056) it seems we may not have 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // a focus manager. Please reopen the bug if you hit this. 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Start the process of animating the opening of the widget. 743f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen animation_.reset(new ui::SlideAnimation(this)); 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDropdownBarHost::~DropdownBarHost() { 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch focus_manager_->RemoveFocusChangeListener(this); 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch focus_tracker_.reset(NULL); 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DropdownBarHost::Show(bool animate) { 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Stores the currently focused view, and tracks focus changes so that we can 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // restore focus when the dropdown widget is closed. 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch focus_tracker_.reset(new views::ExternalFocusTracker(view_, focus_manager_)); 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!animate || disable_animations_during_testing_) { 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch is_visible_ = true; 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch animation_->Reset(1); 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AnimationProgressed(animation_.get()); 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!is_visible_) { 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Don't re-start the animation. 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch is_visible_ = true; 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch animation_->Reset(); 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch animation_->Show(); 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DropdownBarHost::SetFocusAndSelection() { 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->SetFocusAndSelection(true); 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool DropdownBarHost::IsAnimating() const { 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return animation_->is_animating(); 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DropdownBarHost::Hide(bool animate) { 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!IsVisible()) 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (animate && !disable_animations_during_testing_) { 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch animation_->Reset(1.0); 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch animation_->Hide(); 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StopAnimation(); 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch is_visible_ = false; 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch host_->Hide(); 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DropdownBarHost::StopAnimation() { 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch animation_->End(); 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool DropdownBarHost::IsVisible() const { 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return is_visible_; 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// DropdownBarHost, views::FocusChangeListener implementation: 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DropdownBarHost::FocusWillChange(views::View* focused_before, 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::View* focused_now) { 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // First we need to determine if one or both of the views passed in are child 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // views of our view. 13672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen bool our_view_before = focused_before && view_->Contains(focused_before); 13772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen bool our_view_now = focused_now && view_->Contains(focused_now); 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // When both our_view_before and our_view_now are false, it means focus is 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // changing hands elsewhere in the application (and we shouldn't do anything). 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Similarly, when both are true, focus is changing hands within the dropdown 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // widget (and again, we should not do anything). We therefore only need to 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // look at when we gain initial focus and when we loose it. 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!our_view_before && our_view_now) { 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We are gaining focus from outside the dropdown widget so we must register 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // a handler for Escape. 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch RegisterAccelerators(); 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (our_view_before && !our_view_now) { 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We are losing focus to something outside our widget so we restore the 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // original handler for Escape. 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UnregisterAccelerators(); 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 1563f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// DropdownBarHost, ui::AnimationDelegate implementation: 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1583f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid DropdownBarHost::AnimationProgressed(const ui::Animation* animation) { 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // First, we calculate how many pixels to slide the widget. 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Size pref_size = view_->GetPreferredSize(); 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch animation_offset_ = static_cast<int>((1.0 - animation_->GetCurrentValue()) * 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch pref_size.height()); 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This call makes sure it appears in the right location, the size and shape 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // is correct and that it slides in the right direction. 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect dlg_rect = GetDialogPosition(gfx::Rect()); 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetDialogPosition(dlg_rect, false); 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Let the view know if we are animating, and at which offset to draw the 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // edges. 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->set_animation_offset(animation_offset_); 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view_->SchedulePaint(); 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1753f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid DropdownBarHost::AnimationEnded(const ui::Animation* animation) { 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Place the dropdown widget in its fully opened state. 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch animation_offset_ = 0; 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!animation_->IsShowing()) { 180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Animation has finished closing. 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch host_->Hide(); 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch is_visible_ = false; 183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Animation has finished opening. 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// DropdownBarHost protected: 190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DropdownBarHost::ResetFocusTracker() { 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch focus_tracker_.reset(NULL); 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DropdownBarHost::GetWidgetBounds(gfx::Rect* bounds) { 196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(bounds); 197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *bounds = browser_view_->bounds(); 198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DropdownBarHost::UpdateWindowEdges(const gfx::Rect& new_pos) { 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // |w| is used to make it easier to create the part of the polygon that curves 202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the right side of the Find window. It essentially keeps track of the 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // x-pixel position of the right-most background image inside the view. 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(finnur): Let the view tell us how to draw the curves or convert 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // this to a CustomFrameWindow. 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int w = new_pos.width() - 6; // -6 positions us at the left edge of the 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // rightmost background image of the view. 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int h = new_pos.height(); 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This polygon array represents the outline of the background image for the 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // window. Basically, it encompasses only the visible pixels of the 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // concatenated find_dlg_LMR_bg images (where LMR = [left | middle | right]). 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const Path::Point polygon[] = { 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch {0, 0}, {0, 1}, {2, 3}, {2, h - 3}, {4, h - 1}, 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch {4, h}, {w+0, h}, 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch {w+0, h - 1}, {w+1, h - 1}, {w+3, h - 3}, {w+3, 3}, {w+6, 0} 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }; 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Find the largest x and y value in the polygon. 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int max_x = 0, max_y = 0; 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < arraysize(polygon); i++) { 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch max_x = std::max(max_x, static_cast<int>(polygon[i].x)); 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch max_y = std::max(max_y, static_cast<int>(polygon[i].y)); 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We then create the polygon and use SetWindowRgn to force the window to draw 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // only within that area. This region may get reduced in size below. 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Path path(polygon, arraysize(polygon)); 2293f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen ScopedPlatformRegion region(path.CreateNativeRegion()); 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Are we animating? 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (animation_offset() > 0) { 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The animation happens in two steps: First, we clip the window and then in 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // GetWidgetPosition we offset the window position so that it still looks 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // attached to the toolbar as it grows. We clip the window by creating a 235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // rectangle region (that gradually increases as the animation progresses) 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // and find the intersection between the two regions using CombineRgn. 237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // |y| shrinks as the animation progresses from the height of the view down 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // to 0 (and reverses when closing). 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int y = animation_offset(); 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // |y| shrinking means the animation (visible) region gets larger. In other 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // words: the rectangle grows upward (when the widget is opening). 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Path animation_path; 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SkRect animation_rect = { SkIntToScalar(0), SkIntToScalar(y), 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SkIntToScalar(max_x), SkIntToScalar(max_y) }; 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch animation_path.addRect(animation_rect); 2473f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen ScopedPlatformRegion animation_region( 2483f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen animation_path.CreateNativeRegion()); 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch region.Set(Path::IntersectRegions(animation_region.Get(), region.Get())); 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Next, we need to increase the region a little bit to account for the 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // curved edges that the view will draw to make it look like grows out of 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the toolbar. 254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Path::Point left_curve[] = { 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch {0, y+0}, {0, y+1}, {2, y+3}, {2, y+0}, {0, y+0} 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }; 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Path::Point right_curve[] = { 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch {w+3, y+3}, {w+6, y+0}, {w+3, y+0}, {w+3, y+3} 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }; 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Combine the region for the curve on the left with our main region. 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Path left_path(left_curve, arraysize(left_curve)); 2633f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen ScopedPlatformRegion r(left_path.CreateNativeRegion()); 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch region.Set(Path::CombineRegions(r.Get(), region.Get())); 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Combine the region for the curve on the right with our main region. 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Path right_path(right_curve, arraysize(right_curve)); 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch region.Set(Path::CombineRegions(r.Get(), region.Get())); 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Now see if we need to truncate the region because parts of it obscures 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the main window border. 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect widget_bounds; 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetWidgetBounds(&widget_bounds); 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Calculate how much our current position overlaps our boundaries. If we 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // overlap, it means we have too little space to draw the whole widget and 278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // we allow overwriting the scrollbar before we start truncating our widget. 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(brettw) this constant is evil. This is the amount of room we've added 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // to the window size, when we set the region, it can change the size. 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static const int kAddedWidth = 7; 2833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int difference = new_pos.right() - kAddedWidth - widget_bounds.right() - 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::scrollbar_size() + 1; 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (difference > 0) { 286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Path::Point exclude[4]; 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch exclude[0].x = max_x - difference; // Top left corner. 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch exclude[0].y = 0; 289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch exclude[1].x = max_x; // Top right corner. 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch exclude[1].y = 0; 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch exclude[2].x = max_x; // Bottom right corner. 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch exclude[2].y = max_y; 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch exclude[3].x = max_x - difference; // Bottom left corner. 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch exclude[3].y = max_y; 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Subtract this region from the original region. 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Path exclude_path(exclude, arraysize(exclude)); 3013f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen ScopedPlatformRegion exclude_region(exclude_path.CreateNativeRegion()); 302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch region.Set(Path::SubtractRegion(region.Get(), exclude_region.Get())); 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Window takes ownership of the region. 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch host()->SetShape(region.release()); 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DropdownBarHost::RegisterAccelerators() { 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!esc_accel_target_registered_); 31172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen views::Accelerator escape(ui::VKEY_ESCAPE, false, false, false); 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch focus_manager_->RegisterAccelerator(escape, this); 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch esc_accel_target_registered_ = true; 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DropdownBarHost::UnregisterAccelerators() { 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(esc_accel_target_registered_); 31872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen views::Accelerator escape(ui::VKEY_ESCAPE, false, false, false); 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch focus_manager_->UnregisterAccelerator(escape, this); 320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch esc_accel_target_registered_ = false; 321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 322