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/notifications/balloon_view.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <vector>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/message_loop.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/notifications/balloon.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/notifications/balloon_collection.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/notifications/desktop_notification_service.h"
14201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include "chrome/browser/notifications/notification.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/notifications/notification_options_menu_model.h"
16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/views/bubble/bubble_border.h"
1772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/views/notifications/balloon_view_host.h"
18dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/render_view_host.h"
19dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/render_widget_host_view.h"
20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_details.h"
21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_source.h"
22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_type.h"
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/generated_resources.h"
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/theme_resources.h"
253f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "ui/base/animation/slide_animation.h"
2672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h"
2772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/resource/resource_bundle.h"
2872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/canvas_skia.h"
2972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/insets.h"
3072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/native_widget_types.h"
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/controls/button/button.h"
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/controls/button/image_button.h"
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/controls/button/text_button.h"
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/controls/menu/menu_2.h"
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/controls/native/native_view_host.h"
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/painter.h"
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/widget/root_view.h"
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/widget/widget_win.h"
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_LINUX)
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/widget/widget_gtk.h"
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing views::Widget;
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kTopMargin = 2;
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kBottomMargin = 0;
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kLeftMargin = 4;
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kRightMargin = 4;
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kShelfBorderTopOverlap = 0;
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Properties of the dismiss button.
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kDismissButtonWidth = 14;
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kDismissButtonHeight = 14;
583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst int kDismissButtonTopMargin = 6;
593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst int kDismissButtonRightMargin = 6;
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Properties of the options menu.
623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst int kOptionsButtonWidth = 21;
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kOptionsButtonHeight = 14;
643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst int kOptionsButtonTopMargin = 5;
653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst int kOptionsButtonRightMargin = 4;
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Properties of the origin label.
683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst int kLabelLeftMargin = 10;
693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst int kLabelTopMargin = 6;
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Size of the drop shadow.  The shadow is provided by BubbleBorder,
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// not this class.
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kLeftShadowWidth = 0;
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kRightShadowWidth = 0;
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kTopShadowWidth = 0;
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kBottomShadowWidth = 6;
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Optional animation.
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst bool kAnimateEnabled = true;
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The shelf height for the system default font size.  It is scaled
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// with changes in the default font size.
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kDefaultShelfHeight = 22;
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Menu commands
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kRevokePermissionCommand = 0;
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Colors
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst SkColor kControlBarBackgroundColor = SkColorSetRGB(245, 245, 245);
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst SkColor kControlBarTextColor = SkColorSetRGB(125, 125, 125);
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst SkColor kControlBarSeparatorLineColor = SkColorSetRGB(180, 180, 180);
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBalloonViewImpl::BalloonViewImpl(BalloonCollection* collection)
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : balloon_(NULL),
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      collection_(collection),
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      frame_container_(NULL),
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      html_container_(NULL),
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      html_contents_(NULL),
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      method_factory_(this),
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      close_button_(NULL),
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      animation_(NULL),
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      options_menu_model_(NULL),
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      options_menu_menu_(NULL),
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      options_menu_button_(NULL) {
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This object is not to be deleted by the views hierarchy,
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // as it is owned by the balloon.
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  set_parent_owned(false);
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BubbleBorder* bubble_border = new BubbleBorder(BubbleBorder::FLOAT);
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  set_border(bubble_border);
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBalloonViewImpl::~BalloonViewImpl() {
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BalloonViewImpl::Close(bool by_user) {
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MessageLoop::current()->PostTask(FROM_HERE,
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      method_factory_.NewRunnableMethod(
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          &BalloonViewImpl::DelayedClose, by_user));
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Size BalloonViewImpl::GetSize() const {
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // BalloonView has no size if it hasn't been shown yet (which is when
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // balloon_ is set).
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!balloon_)
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return gfx::Size(0, 0);
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return gfx::Size(GetTotalWidth(), GetTotalHeight());
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
13321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenBalloonHost* BalloonViewImpl::GetHost() const {
13421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return html_contents_.get();
13521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
13621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BalloonViewImpl::RunMenu(views::View* source, const gfx::Point& pt) {
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  RunOptionsMenu(pt);
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
141ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BalloonViewImpl::OnDisplayChanged() {
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  collection_->DisplayChanged();
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
145ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BalloonViewImpl::OnWorkAreaChanged() {
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  collection_->DisplayChanged();
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BalloonViewImpl::ButtonPressed(views::Button* sender,
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    const views::Event&) {
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The only button currently is the close button.
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(sender == close_button_);
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Close(true);
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BalloonViewImpl::DelayedClose(bool by_user) {
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  html_contents_->Shutdown();
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  html_container_->CloseNow();
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The BalloonViewImpl has to be detached from frame_container_ now
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // because CloseNow on linux/views destroys the view hierachy
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // asynchronously.
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame_container_->GetRootView()->RemoveAllChildViews(true);
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame_container_->CloseNow();
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  balloon_->OnClose(by_user);
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
16721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsengfx::Size BalloonViewImpl::GetPreferredSize() {
16821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return gfx::Size(1000, 1000);
16921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
17021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BalloonViewImpl::SizeContentsWindow() {
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!html_container_ || !frame_container_)
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Rect contents_rect = GetContentsRectangle();
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  html_container_->SetBounds(contents_rect);
177ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  html_container_->MoveAboveWidget(frame_container_);
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Path path;
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GetContentsMask(contents_rect, &path);
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  html_container_->SetShape(path.CreateNativeRegion());
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
18372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  close_button_->SetBoundsRect(GetCloseButtonBounds());
18472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  options_menu_button_->SetBoundsRect(GetOptionsButtonBounds());
18572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  source_label_->SetBoundsRect(GetLabelBounds());
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BalloonViewImpl::RepositionToBalloon() {
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(frame_container_);
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(html_container_);
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(balloon_);
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!kAnimateEnabled) {
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    frame_container_->SetBounds(
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        gfx::Rect(balloon_->GetPosition().x(), balloon_->GetPosition().y(),
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  GetTotalWidth(), GetTotalHeight()));
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gfx::Rect contents_rect = GetContentsRectangle();
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    html_container_->SetBounds(contents_rect);
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    html_contents_->SetPreferredSize(contents_rect.size());
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    RenderWidgetHostView* view = html_contents_->render_view_host()->view();
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (view)
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      view->SetSize(contents_rect.size());
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  anim_frame_end_ = gfx::Rect(
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      balloon_->GetPosition().x(), balloon_->GetPosition().y(),
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GetTotalWidth(), GetTotalHeight());
209dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  anim_frame_start_ = frame_container_->GetClientAreaScreenBounds();
2103f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  animation_.reset(new ui::SlideAnimation(this));
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  animation_->Show();
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BalloonViewImpl::Update() {
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(html_contents_.get()) << "BalloonView::Update called before Show";
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (html_contents_->render_view_host())
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    html_contents_->render_view_host()->NavigateToURL(
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        balloon_->notification().content_url());
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2213f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid BalloonViewImpl::AnimationProgressed(const ui::Animation* animation) {
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(animation == animation_.get());
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Linear interpolation from start to end position.
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  double e = animation->GetCurrentValue();
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  double s = (1.0 - e);
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Rect frame_position(
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    static_cast<int>(s * anim_frame_start_.x() +
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     e * anim_frame_end_.x()),
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    static_cast<int>(s * anim_frame_start_.y() +
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     e * anim_frame_end_.y()),
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    static_cast<int>(s * anim_frame_start_.width() +
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     e * anim_frame_end_.width()),
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    static_cast<int>(s * anim_frame_start_.height() +
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     e * anim_frame_end_.height()));
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame_container_->SetBounds(frame_position);
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Path path;
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Rect contents_rect = GetContentsRectangle();
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  html_container_->SetBounds(contents_rect);
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GetContentsMask(contents_rect, &path);
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  html_container_->SetShape(path.CreateNativeRegion());
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  html_contents_->SetPreferredSize(contents_rect.size());
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  RenderWidgetHostView* view = html_contents_->render_view_host()->view();
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (view)
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    view->SetSize(contents_rect.size());
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Rect BalloonViewImpl::GetCloseButtonBounds() const {
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return gfx::Rect(
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      width() - kDismissButtonWidth -
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          kDismissButtonRightMargin - kRightShadowWidth,
2553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      kDismissButtonTopMargin,
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      kDismissButtonWidth,
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      kDismissButtonHeight);
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Rect BalloonViewImpl::GetOptionsButtonBounds() const {
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Rect close_rect = GetCloseButtonBounds();
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return gfx::Rect(
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      close_rect.x() - kOptionsButtonWidth - kOptionsButtonRightMargin,
2653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      kOptionsButtonTopMargin,
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      kOptionsButtonWidth,
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      kOptionsButtonHeight);
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Rect BalloonViewImpl::GetLabelBounds() const {
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return gfx::Rect(
2723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      kLeftShadowWidth + kLabelLeftMargin,
2733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      kLabelTopMargin,
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      std::max(0, width() - kOptionsButtonWidth -
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               kRightMargin),
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      kOptionsButtonHeight);
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BalloonViewImpl::Show(Balloon* balloon) {
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  balloon_ = balloon;
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SetBounds(balloon_->GetPosition().x(), balloon_->GetPosition().y(),
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            GetTotalWidth(), GetTotalHeight());
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  const string16 source_label_text = l10n_util::GetStringFUTF16(
2883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      IDS_NOTIFICATION_BALLOON_SOURCE_LABEL,
2893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      balloon->notification().display_source());
2903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  source_label_ = new views::Label(UTF16ToWide(source_label_text));
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddChildView(source_label_);
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  options_menu_button_ = new views::MenuButton(NULL, L"", this, false);
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddChildView(options_menu_button_);
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  close_button_ = new views::ImageButton(this);
2963f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  close_button_->SetTooltipText(UTF16ToWide(l10n_util::GetStringUTF16(
2973f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen      IDS_NOTIFICATION_BALLOON_DISMISS_LABEL)));
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddChildView(close_button_);
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We have to create two windows: one for the contents and one for the
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // frame.  Why?
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // * The contents is an html window which cannot be a
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //   layered window (because it may have child windows for instance).
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // * The frame is a layered window so that we can have nicely rounded
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //   corners using alpha blending (and we may do other alpha blending
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //   effects).
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Unfortunately, layered windows cannot have child windows. (Well, they can
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // but the child windows don't render).
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We carefully keep these two windows in sync to present the illusion of
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // one window to the user.
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We don't let the OS manage the RTL layout of these widgets, because
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // this code is already taking care of correctly reversing the layout.
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Rect contents_rect = GetContentsRectangle();
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  html_contents_.reset(new BalloonViewHost(balloon));
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  html_contents_->SetPreferredSize(gfx::Size(10000, 10000));
318ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  Widget::CreateParams params(Widget::CreateParams::TYPE_POPUP);
319ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  params.mirror_origin_in_rtl = false;
320ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  html_container_ = Widget::CreateWidget(params);
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  html_container_->SetAlwaysOnTop(true);
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  html_container_->Init(NULL, contents_rect);
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  html_container_->SetContentsView(html_contents_->view());
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Rect balloon_rect(x(), y(), GetTotalWidth(), GetTotalHeight());
326ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  params.transparent = true;
327ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  frame_container_ = Widget::CreateWidget(params);
328dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  frame_container_->set_widget_delegate(this);
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame_container_->SetAlwaysOnTop(true);
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame_container_->Init(NULL, balloon_rect);
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame_container_->SetContentsView(this);
332ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  frame_container_->MoveAboveWidget(html_container_);
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  close_button_->SetImage(views::CustomButton::BS_NORMAL,
3353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                          rb.GetBitmapNamed(IDR_TAB_CLOSE));
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  close_button_->SetImage(views::CustomButton::BS_HOT,
3373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                          rb.GetBitmapNamed(IDR_TAB_CLOSE_H));
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  close_button_->SetImage(views::CustomButton::BS_PUSHED,
3393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                          rb.GetBitmapNamed(IDR_TAB_CLOSE_P));
34072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  close_button_->SetBoundsRect(GetCloseButtonBounds());
3413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  close_button_->SetBackground(SK_ColorBLACK,
3423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                               rb.GetBitmapNamed(IDR_TAB_CLOSE),
3433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                               rb.GetBitmapNamed(IDR_TAB_CLOSE_MASK));
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  options_menu_button_->SetIcon(*rb.GetBitmapNamed(IDR_BALLOON_WRENCH));
3463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  options_menu_button_->SetHoverIcon(*rb.GetBitmapNamed(IDR_BALLOON_WRENCH_H));
3473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  options_menu_button_->SetPushedIcon(*rb.GetBitmapNamed(IDR_BALLOON_WRENCH_P));
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  options_menu_button_->set_alignment(views::TextButton::ALIGN_CENTER);
3493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  options_menu_button_->set_border(NULL);
35072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  options_menu_button_->SetBoundsRect(GetOptionsButtonBounds());
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  source_label_->SetFont(rb.GetFont(ResourceBundle::SmallFont));
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  source_label_->SetColor(kControlBarTextColor);
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  source_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
35572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  source_label_->SetBoundsRect(GetLabelBounds());
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SizeContentsWindow();
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  html_container_->Show();
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame_container_->Show();
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  notification_registrar_.Add(this,
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NotificationType::NOTIFY_BALLOON_DISCONNECTED, Source<Balloon>(balloon));
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BalloonViewImpl::RunOptionsMenu(const gfx::Point& pt) {
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CreateOptionsMenu();
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  options_menu_menu_->RunMenuAt(pt, views::Menu2::ALIGN_TOPRIGHT);
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BalloonViewImpl::CreateOptionsMenu() {
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (options_menu_model_.get())
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  options_menu_model_.reset(new NotificationOptionsMenuModel(balloon_));
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  options_menu_menu_.reset(new views::Menu2(options_menu_model_.get()));
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BalloonViewImpl::GetContentsMask(const gfx::Rect& rect,
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      gfx::Path* path) const {
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This rounds the corners, and we also cut out a circle for the close
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // button, since we can't guarantee the ordering of two top-most windows.
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SkScalar radius = SkIntToScalar(BubbleBorder::GetCornerRadius());
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SkScalar spline_radius = radius -
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SkScalarMul(radius, (SK_ScalarSqrt2 - SK_Scalar1) * 4 / 3);
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SkScalar left = SkIntToScalar(0);
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SkScalar top = SkIntToScalar(0);
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SkScalar right = SkIntToScalar(rect.width());
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SkScalar bottom = SkIntToScalar(rect.height());
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  path->moveTo(left, top);
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  path->lineTo(right, top);
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  path->lineTo(right, bottom - radius);
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  path->cubicTo(right, bottom - spline_radius,
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                right - spline_radius, bottom,
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                right - radius, bottom);
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  path->lineTo(left + radius, bottom);
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  path->cubicTo(left + spline_radius, bottom,
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                left, bottom - spline_radius,
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                left, bottom - radius);
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  path->lineTo(left, top);
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  path->close();
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BalloonViewImpl::GetFrameMask(const gfx::Rect& rect,
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   gfx::Path* path) const {
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SkScalar radius = SkIntToScalar(BubbleBorder::GetCornerRadius());
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SkScalar spline_radius = radius -
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SkScalarMul(radius, (SK_ScalarSqrt2 - SK_Scalar1) * 4 / 3);
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SkScalar left = SkIntToScalar(rect.x());
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SkScalar top = SkIntToScalar(rect.y());
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SkScalar right = SkIntToScalar(rect.right());
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SkScalar bottom = SkIntToScalar(rect.bottom());
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  path->moveTo(left, bottom);
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  path->lineTo(left, top + radius);
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  path->cubicTo(left, top + spline_radius,
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                left + spline_radius, top,
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                left + radius, top);
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  path->lineTo(right - radius, top);
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  path->cubicTo(right - spline_radius, top,
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                right, top + spline_radius,
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                right, top + radius);
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  path->lineTo(right, bottom);
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  path->lineTo(left, bottom);
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  path->close();
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Point BalloonViewImpl::GetContentsOffset() const {
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return gfx::Point(kLeftShadowWidth + kLeftMargin,
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    kTopShadowWidth + kTopMargin);
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BalloonViewImpl::GetShelfHeight() const {
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(johnnyg): add scaling here.
435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return kDefaultShelfHeight;
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BalloonViewImpl::GetBalloonFrameHeight() const {
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return GetTotalHeight() - GetShelfHeight();
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BalloonViewImpl::GetTotalWidth() const {
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return balloon_->content_size().width()
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      + kLeftMargin + kRightMargin + kLeftShadowWidth + kRightShadowWidth;
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BalloonViewImpl::GetTotalHeight() const {
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return balloon_->content_size().height()
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      + kTopMargin + kBottomMargin + kTopShadowWidth + kBottomShadowWidth
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      + GetShelfHeight();
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Rect BalloonViewImpl::GetContentsRectangle() const {
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!frame_container_)
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return gfx::Rect();
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Size content_size = balloon_->content_size();
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Point offset = GetContentsOffset();
459dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  gfx::Rect frame_rect = frame_container_->GetWindowScreenBounds();
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return gfx::Rect(frame_rect.x() + offset.x(),
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   frame_rect.y() + GetShelfHeight() + offset.y(),
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   content_size.width(),
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   content_size.height());
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
466dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid BalloonViewImpl::OnPaint(gfx::Canvas* canvas) {
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(canvas);
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Paint the menu bar area white, with proper rounded corners.
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Path path;
47072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  gfx::Rect rect = GetContentsBounds();
471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  rect.set_height(GetShelfHeight());
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GetFrameMask(rect, &path);
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SkPaint paint;
475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  paint.setAntiAlias(true);
476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  paint.setColor(kControlBarBackgroundColor);
477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  canvas->AsCanvasSkia()->drawPath(path, paint);
478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Draw a 1-pixel gray line between the content and the menu bar.
480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int line_width = GetTotalWidth() - kLeftMargin - kRightMargin;
481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  canvas->FillRectInt(kControlBarSeparatorLineColor,
482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      kLeftMargin, 1 + GetShelfHeight(), line_width, 1);
483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
484dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  View::OnPaint(canvas);
485dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  OnPaintBorder(canvas);
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
488ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BalloonViewImpl::OnBoundsChanged(const gfx::Rect& previous_bounds) {
489ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SizeContentsWindow();
490ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
491ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BalloonViewImpl::Observe(NotificationType type,
493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              const NotificationSource& source,
494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              const NotificationDetails& details) {
495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (type != NotificationType::NOTIFY_BALLOON_DISCONNECTED) {
496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED();
497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If the renderer process attached to this balloon is disconnected
501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // (e.g., because of a crash), we want to close the balloon.
502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  notification_registrar_.Remove(this,
503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NotificationType::NOTIFY_BALLOON_DISCONNECTED, Source<Balloon>(balloon_));
504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Close(false);
505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
506