1// Copyright (c) 2011 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/blocked_content_container.h"
6
7#include "content/browser/tab_contents/tab_contents.h"
8#include "ui/gfx/rect.h"
9
10// static
11const size_t BlockedContentContainer::kImpossibleNumberOfPopups = 30;
12
13struct BlockedContentContainer::BlockedContent {
14  BlockedContent(TabContents* tab_contents,
15                 WindowOpenDisposition disposition,
16                 const gfx::Rect& bounds,
17                 bool user_gesture)
18      : tab_contents(tab_contents),
19        disposition(disposition),
20        bounds(bounds),
21        user_gesture(user_gesture) {
22  }
23
24  TabContents* tab_contents;
25  WindowOpenDisposition disposition;
26  gfx::Rect bounds;
27  bool user_gesture;
28};
29
30BlockedContentContainer::BlockedContentContainer(TabContents* owner)
31    : owner_(owner) {
32}
33
34BlockedContentContainer::~BlockedContentContainer() {}
35
36void BlockedContentContainer::AddTabContents(TabContents* tab_contents,
37                                             WindowOpenDisposition disposition,
38                                             const gfx::Rect& bounds,
39                                             bool user_gesture) {
40  if (blocked_contents_.size() == (kImpossibleNumberOfPopups - 1)) {
41    delete tab_contents;
42    VLOG(1) << "Warning: Renderer is sending more popups to us than should be "
43               "possible. Renderer compromised?";
44    return;
45  }
46
47  blocked_contents_.push_back(
48      BlockedContent(tab_contents, disposition, bounds, user_gesture));
49  tab_contents->set_delegate(this);
50  // Since the new tab_contents will not be showed, call WasHidden to change
51  // its status on both RenderViewHost and RenderView.
52  tab_contents->WasHidden();
53  if (blocked_contents_.size() == 1)
54    owner_->PopupNotificationVisibilityChanged(true);
55}
56
57void BlockedContentContainer::LaunchForContents(TabContents* tab_contents) {
58  // Open the popup.
59  for (BlockedContents::iterator i(blocked_contents_.begin());
60       i != blocked_contents_.end(); ++i) {
61    if (i->tab_contents == tab_contents) {
62      // To support the owner blocking the content again we copy and erase
63      // before attempting to add.
64      BlockedContent content(*i);
65      blocked_contents_.erase(i);
66      i = blocked_contents_.end();
67      tab_contents->set_delegate(NULL);
68      // We needn't call WasRestored to change its status because the
69      // TabContents::AddNewContents will do it.
70      owner_->AddOrBlockNewContents(tab_contents,
71                                    content.disposition,
72                                    content.bounds,
73                                    content.user_gesture);
74      break;
75    }
76  }
77
78  if (blocked_contents_.empty())
79    Destroy();
80}
81
82size_t BlockedContentContainer::GetBlockedContentsCount() const {
83  return blocked_contents_.size();
84}
85
86void BlockedContentContainer::GetBlockedContents(
87    std::vector<TabContents*>* blocked_contents) const {
88  DCHECK(blocked_contents);
89  for (BlockedContents::const_iterator i(blocked_contents_.begin());
90       i != blocked_contents_.end(); ++i)
91    blocked_contents->push_back(i->tab_contents);
92}
93
94void BlockedContentContainer::Destroy() {
95  for (BlockedContents::iterator i(blocked_contents_.begin());
96       i != blocked_contents_.end(); ++i) {
97    TabContents* tab_contents = i->tab_contents;
98    tab_contents->set_delegate(NULL);
99    delete tab_contents;
100  }
101  blocked_contents_.clear();
102  owner_->WillCloseBlockedContentContainer(this);
103  delete this;
104}
105
106// Overridden from TabContentsDelegate:
107void BlockedContentContainer::OpenURLFromTab(TabContents* source,
108                                             const GURL& url,
109                                             const GURL& referrer,
110                                             WindowOpenDisposition disposition,
111                                             PageTransition::Type transition) {
112  owner_->OpenURL(url, referrer, disposition, transition);
113}
114
115void BlockedContentContainer::AddNewContents(TabContents* source,
116                                             TabContents* new_contents,
117                                             WindowOpenDisposition disposition,
118                                             const gfx::Rect& initial_position,
119                                             bool user_gesture) {
120  owner_->AddOrBlockNewContents(
121      new_contents, disposition, initial_position, user_gesture);
122}
123
124void BlockedContentContainer::CloseContents(TabContents* source) {
125  for (BlockedContents::iterator i(blocked_contents_.begin());
126       i != blocked_contents_.end(); ++i) {
127    TabContents* tab_contents = i->tab_contents;
128    if (tab_contents == source) {
129      tab_contents->set_delegate(NULL);
130      blocked_contents_.erase(i);
131      delete tab_contents;
132      break;
133    }
134  }
135}
136
137void BlockedContentContainer::MoveContents(TabContents* source,
138                                           const gfx::Rect& new_bounds) {
139  for (BlockedContents::iterator i(blocked_contents_.begin());
140       i != blocked_contents_.end(); ++i) {
141    if (i->tab_contents == source) {
142      i->bounds = new_bounds;
143      break;
144    }
145  }
146}
147
148bool BlockedContentContainer::IsPopup(const TabContents* source) const {
149  // Assume everything added is a popup. This may turn out to be wrong, but
150  // callers don't cache this information so it should be fine if the value ends
151  // up changing.
152  return true;
153}
154
155TabContents* BlockedContentContainer::GetConstrainingContents(
156    TabContents* source) {
157  return owner_;
158}
159