Index: content/browser/frame_host/frame_tree_node.cc |
diff --git a/content/browser/frame_host/frame_tree_node.cc b/content/browser/frame_host/frame_tree_node.cc |
index 08254c9d2d44aafdbfd321f9c38e379bde819bee..b553503b49bdeea8fc3319e153e5ac56a6d9fd7a 100644 |
--- a/content/browser/frame_host/frame_tree_node.cc |
+++ b/content/browser/frame_host/frame_tree_node.cc |
@@ -37,6 +37,24 @@ const double kLoadingProgressDone = 1.0; |
} // namespace |
+// This observer watches the opener of its owner FrameTreeNode and clears the |
+// owner's opener if the opener is destroyed. |
+class FrameTreeNode::OpenerDestroyedObserver : public FrameTreeNode::Observer { |
+ public: |
+ OpenerDestroyedObserver(FrameTreeNode* owner) : owner_(owner) {} |
+ |
+ // FrameTreeNode::Observer |
+ void OnFrameTreeNodeDestroyed(FrameTreeNode* node) override { |
+ CHECK_EQ(owner_->opener(), node); |
+ owner_->SetOpener(nullptr); |
+ } |
+ |
+ private: |
+ FrameTreeNode* owner_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(OpenerDestroyedObserver); |
+}; |
+ |
int FrameTreeNode::next_frame_tree_node_id_ = 1; |
// static |
@@ -65,6 +83,8 @@ FrameTreeNode::FrameTreeNode(FrameTree* frame_tree, |
manager_delegate), |
frame_tree_node_id_(next_frame_tree_node_id_++), |
parent_(NULL), |
+ opener_(nullptr), |
+ opener_observer_(nullptr), |
replication_state_(scope, name, sandbox_flags), |
// Effective sandbox flags also need to be set, since initial sandbox |
// flags should apply to the initial empty document in the frame. |
@@ -78,10 +98,22 @@ FrameTreeNode::FrameTreeNode(FrameTree* frame_tree, |
FrameTreeNode::~FrameTreeNode() { |
frame_tree_->FrameRemoved(this); |
+ FOR_EACH_OBSERVER(Observer, observers_, OnFrameTreeNodeDestroyed(this)); |
+ |
+ if (opener_) |
+ opener_->RemoveObserver(opener_observer_.get()); |
g_frame_tree_node_id_map.Get().erase(frame_tree_node_id_); |
} |
+void FrameTreeNode::AddObserver(Observer* observer) { |
+ observers_.AddObserver(observer); |
+} |
+ |
+void FrameTreeNode::RemoveObserver(Observer* observer) { |
+ observers_.RemoveObserver(observer); |
+} |
+ |
bool FrameTreeNode::IsMainFrame() const { |
return frame_tree_->root() == this; |
} |
@@ -139,6 +171,21 @@ void FrameTreeNode::ResetForNewProcess() { |
old_children.clear(); // May notify observers. |
} |
+void FrameTreeNode::SetOpener(FrameTreeNode* opener) { |
+ if (opener_) { |
+ opener_->RemoveObserver(opener_observer_.get()); |
+ opener_observer_.reset(); |
+ } |
+ |
+ opener_ = opener; |
+ |
+ if (opener_) { |
+ if (!opener_observer_) |
+ opener_observer_ = make_scoped_ptr(new OpenerDestroyedObserver(this)); |
+ opener_->AddObserver(opener_observer_.get()); |
+ } |
+} |
+ |
void FrameTreeNode::SetCurrentOrigin(const url::Origin& origin) { |
if (!origin.IsSameAs(replication_state_.origin)) |
render_manager_.OnDidUpdateOrigin(origin); |