| // Copyright 2022 The Cobalt Authors. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "cobalt/web/message_port.h" |
| |
| #include <memory> |
| #include <string> |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/bind_helpers.h" |
| #include "base/logging.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/task_runner.h" |
| #include "cobalt/script/environment_settings.h" |
| #include "cobalt/web/context.h" |
| #include "cobalt/web/event.h" |
| #include "cobalt/web/event_target.h" |
| #include "cobalt/web/message_event.h" |
| |
| namespace cobalt { |
| namespace web { |
| |
| void MessagePort::EntangleWithEventTarget(web::EventTarget* event_target) { |
| { |
| base::AutoLock lock(mutex_); |
| if (event_target_ && (event_target != event_target_)) { |
| CloseLocked(); |
| } |
| if (!event_target) { |
| return; |
| } |
| event_target_ = event_target; |
| } |
| DCHECK(target_task_runner()); |
| target_task_runner()->PostTask( |
| FROM_HERE, |
| base::BindOnce(&Context::AddEnvironmentSettingsChangeObserver, |
| base::Unretained(context()), base::Unretained(this))); |
| remove_environment_settings_change_observer_ = |
| base::BindOnce(&Context::RemoveEnvironmentSettingsChangeObserver, |
| base::Unretained(context()), base::Unretained(this)); |
| |
| target_task_runner()->PostTask( |
| FROM_HERE, |
| base::Bind( |
| [](MessagePort* message_port, |
| web::EventTarget* |
| event_target) { // The first time a MessagePort object's |
| // onmessage IDL attribute is set, the |
| // port's port message queue must be enabled, as if the start() |
| // method had been called. |
| // https://html.spec.whatwg.org/commit-snapshots/465a6b672c703054de278b0f8133eb3ad33d93f4/#messageport |
| if (event_target->HasEventListener(base::Tokens::message())) { |
| message_port->Start(); |
| } else { |
| event_target->AddEventListenerRegistrationCallback( |
| message_port, base::Tokens::message(), |
| base::BindOnce(&MessagePort::Start, |
| base::Unretained(message_port))); |
| } |
| }, |
| base::Unretained(this), base::Unretained(event_target))); |
| } |
| |
| void MessagePort::Start() { |
| // The start() method steps are to enable this's port message queue, if it is |
| // not already enabled. |
| // https://html.spec.whatwg.org/commit-snapshots/465a6b672c703054de278b0f8133eb3ad33d93f4/#dom-messageport-start |
| base::AutoLock lock(mutex_); |
| if (event_target_) { |
| enabled_ = true; |
| for (auto& message : unshipped_messages_) { |
| PostMessageSerializedLocked(std::move(message)); |
| } |
| unshipped_messages_.clear(); |
| } |
| } |
| |
| void MessagePort::Close() { |
| base::AutoLock lock(mutex_); |
| CloseLocked(); |
| } |
| |
| void MessagePort::CloseLocked() { |
| unshipped_messages_.clear(); |
| if (!event_target_) { |
| return; |
| } |
| event_target_->RemoveEventListenerRegistrationCallbacks(this); |
| if (remove_environment_settings_change_observer_) { |
| std::move(remove_environment_settings_change_observer_).Run(); |
| } |
| event_target_ = nullptr; |
| } |
| |
| void MessagePort::PostMessage(const script::ValueHandleHolder& message) { |
| auto structured_clone = std::make_unique<script::StructuredClone>(message); |
| { |
| base::AutoLock lock(mutex_); |
| if (!(event_target_ && enabled_)) { |
| unshipped_messages_.push_back(std::move(structured_clone)); |
| return; |
| } |
| PostMessageSerializedLocked(std::move(structured_clone)); |
| } |
| } |
| |
| void MessagePort::PostMessageSerializedLocked( |
| std::unique_ptr<script::StructuredClone> structured_clone) { |
| if (!structured_clone || !event_target_ || !enabled_ || |
| structured_clone->failed()) { |
| return; |
| } |
| // TODO: Forward the location of the origating API call to the PostTask |
| // call. |
| // https://html.spec.whatwg.org/multipage/workers.html#handler-worker-onmessage |
| // TODO: Update MessageEvent to support more types. (b/227665847) |
| // TODO: Remove dependency of MessageEvent on net iobuffer (b/227665847) |
| target_task_runner()->PostTask( |
| FROM_HERE, |
| base::BindOnce( |
| [](base::WeakPtr<web::EventTarget> event_target, |
| std::unique_ptr<script::StructuredClone> structured_clone) { |
| event_target->DispatchEvent(new web::MessageEvent( |
| base::Tokens::message(), std::move(structured_clone))); |
| }, |
| event_target_->AsWeakPtr(), std::move(structured_clone))); |
| } |
| |
| } // namespace web |
| } // namespace cobalt |