| // Copyright 2018 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "ios/web/js_messaging/web_frames_manager_impl.h" |
| |
| #import "base/strings/string_util.h" |
| #import "base/strings/sys_string_conversions.h" |
| #import "base/strings/utf_string_conversions.h" |
| #import "ios/web/public/js_messaging/web_frame.h" |
| |
| namespace web { |
| |
| #pragma mark - WebFramesManagerImpl |
| |
| WebFramesManagerImpl::WebFramesManagerImpl() : weak_factory_(this) {} |
| |
| WebFramesManagerImpl::~WebFramesManagerImpl() = default; |
| |
| bool WebFramesManagerImpl::AddFrame(std::unique_ptr<WebFrame> frame) { |
| DCHECK(frame); |
| DCHECK(!frame->GetFrameId().empty()); |
| if (frame->IsMainFrame()) { |
| if (main_web_frame_) { |
| // A main frame is already registered, ignore duplicate registration |
| // message. |
| return false; |
| } |
| main_web_frame_ = frame.get(); |
| } |
| DCHECK(web_frames_.count(frame->GetFrameId()) == 0); |
| std::string frame_id = frame->GetFrameId(); |
| WebFrame* added_frame = frame.get(); |
| web_frames_[frame_id] = std::move(frame); |
| |
| for (auto& observer : observers_) { |
| observer.WebFrameBecameAvailable(this, added_frame); |
| } |
| return true; |
| } |
| |
| void WebFramesManagerImpl::RemoveFrameWithId(const std::string& frame_id) { |
| for (auto& observer : observers_) { |
| observer.WebFrameBecameUnavailable(this, frame_id); |
| } |
| |
| DCHECK(!frame_id.empty()); |
| // If the removed frame is a main frame, it should be the current one. |
| DCHECK(web_frames_.count(frame_id) == 0 || |
| !web_frames_[frame_id]->IsMainFrame() || |
| main_web_frame_ == web_frames_[frame_id].get()); |
| if (web_frames_.count(frame_id) == 0) { |
| return; |
| } |
| if (main_web_frame_ && main_web_frame_->GetFrameId() == frame_id) { |
| main_web_frame_ = nullptr; |
| } |
| // The web::WebFrame destructor can call some callbacks that will try to |
| // access the frame via GetFrameWithId. This can lead to a reentrancy issue |
| // on `web_frames_`. |
| // To avoid this issue, keep the frame alive during the map operation and |
| // destroy it after. |
| auto keep_frame_alive = std::move(web_frames_[frame_id]); |
| web_frames_.erase(frame_id); |
| } |
| |
| void WebFramesManagerImpl::RemoveAllWebFrames() { |
| std::set<std::string> frame_ids; |
| for (const auto& it : web_frames_) { |
| frame_ids.insert(it.first); |
| } |
| for (std::string frame_id : frame_ids) { |
| RemoveFrameWithId(frame_id); |
| } |
| } |
| |
| #pragma mark - WebFramesManager |
| |
| void WebFramesManagerImpl::AddObserver(Observer* observer) { |
| observers_.AddObserver(observer); |
| } |
| |
| void WebFramesManagerImpl::RemoveObserver(Observer* observer) { |
| observers_.RemoveObserver(observer); |
| } |
| |
| std::set<WebFrame*> WebFramesManagerImpl::GetAllWebFrames() { |
| std::set<WebFrame*> frames; |
| for (const auto& it : web_frames_) { |
| frames.insert(it.second.get()); |
| } |
| return frames; |
| } |
| |
| WebFrame* WebFramesManagerImpl::GetMainWebFrame() { |
| return main_web_frame_; |
| } |
| |
| WebFrame* WebFramesManagerImpl::GetFrameWithId(const std::string& frame_id) { |
| if (frame_id.empty()) { |
| return nullptr; |
| } |
| |
| auto web_frames_it = web_frames_.find(base::ToLowerASCII(frame_id)); |
| return web_frames_it == web_frames_.end() ? nullptr |
| : web_frames_it->second.get(); |
| } |
| |
| } // namespace web |