forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
bubble_manager.cc
139 lines (113 loc) · 4.41 KB
/
bubble_manager.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/bubble/bubble_manager.h"
#include <utility>
#include <vector>
#include "components/bubble/bubble_controller.h"
#include "components/bubble/bubble_delegate.h"
BubbleManager::BubbleManager() : manager_state_(SHOW_BUBBLES) {}
BubbleManager::~BubbleManager() {
FinalizePendingRequests();
}
BubbleReference BubbleManager::ShowBubble(
std::unique_ptr<BubbleDelegate> bubble) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK_NE(manager_state_, ITERATING_BUBBLES);
DCHECK(bubble);
std::unique_ptr<BubbleController> controller(
new BubbleController(this, std::move(bubble)));
BubbleReference bubble_ref = controller->AsWeakPtr();
switch (manager_state_) {
case SHOW_BUBBLES:
controller->Show();
controllers_.push_back(std::move(controller));
for (auto& observer : observers_)
observer.OnBubbleShown(bubble_ref);
break;
case NO_MORE_BUBBLES:
for (auto& observer : observers_)
observer.OnBubbleNeverShown(controller->AsWeakPtr());
break;
default:
NOTREACHED();
break;
}
return bubble_ref;
}
bool BubbleManager::CloseBubble(BubbleReference bubble,
BubbleCloseReason reason) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK_NE(manager_state_, ITERATING_BUBBLES);
return CloseAllMatchingBubbles(bubble.get(), nullptr, reason);
}
void BubbleManager::CloseAllBubbles(BubbleCloseReason reason) {
// The following close reasons don't make sense for multiple bubbles:
DCHECK_NE(reason, BUBBLE_CLOSE_ACCEPTED);
DCHECK_NE(reason, BUBBLE_CLOSE_CANCELED);
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK_NE(manager_state_, ITERATING_BUBBLES);
CloseAllMatchingBubbles(nullptr, nullptr, reason);
}
void BubbleManager::UpdateAllBubbleAnchors() {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK_NE(manager_state_, ITERATING_BUBBLES);
// Guard against bubbles being added or removed while iterating the bubbles.
ManagerState original_state = manager_state_;
manager_state_ = ITERATING_BUBBLES;
for (auto& controller : controllers_)
controller->UpdateAnchorPosition();
manager_state_ = original_state;
}
void BubbleManager::AddBubbleManagerObserver(BubbleManagerObserver* observer) {
observers_.AddObserver(observer);
}
void BubbleManager::RemoveBubbleManagerObserver(
BubbleManagerObserver* observer) {
observers_.RemoveObserver(observer);
}
size_t BubbleManager::GetBubbleCountForTesting() const {
return controllers_.size();
}
void BubbleManager::FinalizePendingRequests() {
// Return if already "Finalized".
if (manager_state_ == NO_MORE_BUBBLES)
return;
manager_state_ = NO_MORE_BUBBLES;
CloseAllBubbles(BUBBLE_CLOSE_FORCED);
}
void BubbleManager::CloseBubblesOwnedBy(const content::RenderFrameHost* frame) {
CloseAllMatchingBubbles(nullptr, frame, BUBBLE_CLOSE_FRAME_DESTROYED);
}
bool BubbleManager::CloseAllMatchingBubbles(
BubbleController* bubble,
const content::RenderFrameHost* owner,
BubbleCloseReason reason) {
// Specifying both an owning frame and a particular bubble to close doesn't
// make sense. If we have a frame, all bubbles owned by that frame need to
// have the opportunity to close. If we want to close a specific bubble, then
// it should get the close event regardless of which frame owns it. On the
// other hand, OR'ing the conditions needs a special case in order to be able
// to close all bubbles, so we disallow passing both until a need appears.
DCHECK(!bubble || !owner);
std::vector<std::unique_ptr<BubbleController>> close_queue;
// Guard against bubbles being added or removed while iterating the bubbles.
ManagerState original_state = manager_state_;
manager_state_ = ITERATING_BUBBLES;
for (auto i = controllers_.begin(); i != controllers_.end();) {
if ((!bubble || bubble == (*i).get()) &&
(!owner || (*i)->OwningFrameIs(owner)) && (*i)->ShouldClose(reason)) {
close_queue.push_back(std::move(*i));
i = controllers_.erase(i);
} else {
++i;
}
}
manager_state_ = original_state;
for (auto& controller : close_queue) {
controller->DoClose(reason);
for (auto& observer : observers_)
observer.OnBubbleClosed(controller->AsWeakPtr(), reason);
}
return !close_queue.empty();
}