forked from mirrors/gecko-dev
Backed out changeset bfe390ad771b (bug 1583251) Backed out changeset 0113c698b44d (bug 1583251) Backed out changeset 248ad59168dd (bug 1583251) Backed out changeset 5d5e3dc17118 (bug 1583251) Backed out changeset 9e9eaa78c436 (bug 1583251)
147 lines
5.1 KiB
C++
147 lines
5.1 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "MessageEventRunnable.h"
|
|
|
|
#include "mozilla/dom/MessageEvent.h"
|
|
#include "mozilla/dom/MessageEventBinding.h"
|
|
#include "mozilla/TimelineConsumers.h"
|
|
#include "mozilla/WorkerTimelineMarker.h"
|
|
#include "nsQueryObject.h"
|
|
#include "WorkerPrivate.h"
|
|
#include "WorkerScope.h"
|
|
|
|
namespace mozilla {
|
|
namespace dom {
|
|
|
|
MessageEventRunnable::MessageEventRunnable(WorkerPrivate* aWorkerPrivate,
|
|
TargetAndBusyBehavior aBehavior)
|
|
: WorkerDebuggeeRunnable(aWorkerPrivate, aBehavior),
|
|
StructuredCloneHolder(CloningSupported, TransferringSupported,
|
|
StructuredCloneScope::SameProcessDifferentThread) {}
|
|
|
|
bool MessageEventRunnable::DispatchDOMEvent(JSContext* aCx,
|
|
WorkerPrivate* aWorkerPrivate,
|
|
DOMEventTargetHelper* aTarget,
|
|
bool aIsMainThread) {
|
|
nsCOMPtr<nsIGlobalObject> parent = aTarget->GetParentObject();
|
|
|
|
// For some workers without window, parent is null and we try to find it
|
|
// from the JS Context.
|
|
if (!parent) {
|
|
JS::Rooted<JSObject*> globalObject(aCx, JS::CurrentGlobalOrNull(aCx));
|
|
if (NS_WARN_IF(!globalObject)) {
|
|
return false;
|
|
}
|
|
|
|
parent = xpc::NativeGlobal(globalObject);
|
|
if (NS_WARN_IF(!parent)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
MOZ_ASSERT(parent);
|
|
|
|
JS::Rooted<JS::Value> messageData(aCx);
|
|
IgnoredErrorResult rv;
|
|
|
|
UniquePtr<AbstractTimelineMarker> start;
|
|
UniquePtr<AbstractTimelineMarker> end;
|
|
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
|
|
bool isTimelineRecording = timelines && !timelines->IsEmpty();
|
|
|
|
if (isTimelineRecording) {
|
|
start = MakeUnique<WorkerTimelineMarker>(
|
|
aIsMainThread
|
|
? ProfileTimelineWorkerOperationType::DeserializeDataOnMainThread
|
|
: ProfileTimelineWorkerOperationType::DeserializeDataOffMainThread,
|
|
MarkerTracingType::START);
|
|
}
|
|
|
|
Read(parent, aCx, &messageData, rv);
|
|
|
|
if (isTimelineRecording) {
|
|
end = MakeUnique<WorkerTimelineMarker>(
|
|
aIsMainThread
|
|
? ProfileTimelineWorkerOperationType::DeserializeDataOnMainThread
|
|
: ProfileTimelineWorkerOperationType::DeserializeDataOffMainThread,
|
|
MarkerTracingType::END);
|
|
timelines->AddMarkerForAllObservedDocShells(start);
|
|
timelines->AddMarkerForAllObservedDocShells(end);
|
|
}
|
|
|
|
if (NS_WARN_IF(rv.Failed())) {
|
|
DispatchError(aCx, aTarget);
|
|
return false;
|
|
}
|
|
|
|
Sequence<OwningNonNull<MessagePort>> ports;
|
|
if (!TakeTransferredPortsAsSequence(ports)) {
|
|
DispatchError(aCx, aTarget);
|
|
return false;
|
|
}
|
|
|
|
RefPtr<MessageEvent> event = new MessageEvent(aTarget, nullptr, nullptr);
|
|
event->InitMessageEvent(nullptr, NS_LITERAL_STRING("message"), CanBubble::eNo,
|
|
Cancelable::eNo, messageData, EmptyString(),
|
|
EmptyString(), nullptr, ports);
|
|
|
|
event->SetTrusted(true);
|
|
|
|
aTarget->DispatchEvent(*event);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool MessageEventRunnable::WorkerRun(JSContext* aCx,
|
|
WorkerPrivate* aWorkerPrivate) {
|
|
if (mBehavior == ParentThreadUnchangedBusyCount) {
|
|
// Don't fire this event if the JS object has been disconnected from the
|
|
// private object.
|
|
if (!aWorkerPrivate->IsAcceptingEvents()) {
|
|
return true;
|
|
}
|
|
|
|
// Once a window has frozen its workers, their
|
|
// mMainThreadDebuggeeEventTargets should be paused, and their
|
|
// WorkerDebuggeeRunnables should not be being executed. The same goes for
|
|
// WorkerDebuggeeRunnables sent from child to parent workers, but since a
|
|
// frozen parent worker runs only control runnables anyway, that is taken
|
|
// care of naturally.
|
|
MOZ_ASSERT(!aWorkerPrivate->IsFrozen());
|
|
|
|
// Similarly for paused windows; all its workers should have been informed.
|
|
// (Subworkers are unaffected by paused windows.)
|
|
MOZ_ASSERT(!aWorkerPrivate->IsParentWindowPaused());
|
|
|
|
aWorkerPrivate->AssertInnerWindowIsCorrect();
|
|
|
|
return DispatchDOMEvent(aCx, aWorkerPrivate,
|
|
aWorkerPrivate->ParentEventTargetRef(),
|
|
!aWorkerPrivate->GetParent());
|
|
}
|
|
|
|
MOZ_ASSERT(aWorkerPrivate == GetWorkerPrivateFromContext(aCx));
|
|
|
|
return DispatchDOMEvent(aCx, aWorkerPrivate, aWorkerPrivate->GlobalScope(),
|
|
false);
|
|
}
|
|
|
|
void MessageEventRunnable::DispatchError(JSContext* aCx,
|
|
DOMEventTargetHelper* aTarget) {
|
|
RootedDictionary<MessageEventInit> init(aCx);
|
|
init.mBubbles = false;
|
|
init.mCancelable = false;
|
|
|
|
RefPtr<Event> event = MessageEvent::Constructor(
|
|
aTarget, NS_LITERAL_STRING("messageerror"), init);
|
|
event->SetTrusted(true);
|
|
|
|
aTarget->DispatchEvent(*event);
|
|
}
|
|
|
|
} // namespace dom
|
|
} // namespace mozilla
|