blob: 27a1fc04ad71b3b6a3115d4c64e0b4d0cf8b3e5f [file] [log] [blame]
// Copyright 2021 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/user_education/common/help_bubble.h"
#include "base/auto_reset.h"
#include "base/notreached.h"
namespace user_education {
HelpBubble::HelpBubble()
: on_close_callbacks_(std::make_unique<CallbackList>()) {}
HelpBubble::~HelpBubble() {
// Derived classes must call Close() in destructor lest the bubble be
// destroyed without cleaning up the framework-specific implementation. Since
// Close() itself depends on framework-specific logic, however, it cannot be
// called here, as virtual functions are no longer available in the base
// destructor.
CHECK(is_closed());
}
bool HelpBubble::Close() {
// This prevents us from re-entrancy during CloseBubbleImpl() or after the
// bubble is closed.
if (is_closed() || closing_)
return false;
{
// Prevent re-entrancy until is_closed() becomes true, which happens during
// NotifyBubbleClosed().
base::AutoReset<bool> closing_guard(&closing_, true);
CloseBubbleImpl();
}
// This call could delete `this` so no code can come after it.
NotifyBubbleClosed();
return true;
}
void HelpBubble::OnAnchorBoundsChanged() {}
gfx::Rect HelpBubble::GetBoundsInScreen() const {
return gfx::Rect();
}
base::CallbackListSubscription HelpBubble::AddOnCloseCallback(
ClosedCallback callback) {
if (is_closed()) {
NOTREACHED();
return base::CallbackListSubscription();
}
return on_close_callbacks_->Add(std::move(callback));
}
void HelpBubble::NotifyBubbleClosed() {
// We can't destruct the callback list during callbacks, so ensure that it
// sticks around until the callbacks are all finished. This also has the side
// effect of making is_closed() true since it resets the value of
// `on_close_callbacks_`.
std::unique_ptr<CallbackList> temp = std::move(on_close_callbacks_);
if (temp)
temp->Notify(this);
}
} // namespace user_education