Bug 1526406 - Part 1: Add support for observers to JS Window Actor Protocols. r=nika

Differential Revision: https://phabricator.services.mozilla.com/D21364

--HG--
extra : moz-landing-system : lando
This commit is contained in:
John Dai 2019-03-01 18:24:55 +00:00
Родитель e4b6f46368
Коммит 834792ab94
3 изменённых файлов: 114 добавлений и 2 удалений

Просмотреть файл

@ -609,6 +609,18 @@ dictionary WindowActorChildOptions : WindowActorSidedOptions {
* it will trigger actor creation, and then forward the event to the actor.
*/
record<DOMString, AddEventListenerOptions> events;
/**
* Array of observer topics to listen to. A observer will be added for each
* topic in the list.
*
* Observers in the list much use the nsGlobalWindowInner object as their topic,
* and the events will only be dispatched to the corresponding window actor. If
* additional observer notifications are needed with different listening
* conditions, please file a bug in DOM requesting support for the subject
* required to be added to JS WindowActor objects.
**/
sequence<ByteString> observers;
};
enum Base64URLDecodePadding {

Просмотреть файл

@ -87,9 +87,11 @@ nsresult CallJSActorMethod(nsWrapperCache* aActor, const char* aName,
* This object also can act as a carrier for methods and other state related to
* a single protocol managed by the JSWindowActorService.
*/
class JSWindowActorProtocol final : public nsIDOMEventListener {
class JSWindowActorProtocol final : public nsIObserver,
public nsIDOMEventListener {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
NS_DECL_NSIDOMEVENTLISTENER
static already_AddRefed<JSWindowActorProtocol> FromIPC(
@ -114,6 +116,7 @@ class JSWindowActorProtocol final : public nsIDOMEventListener {
struct ChildSide : public Sided {
nsTArray<EventDecl> mEvents;
nsTArray<nsCString> mObservers;
};
const nsAString& Name() const { return mName; }
@ -122,6 +125,8 @@ class JSWindowActorProtocol final : public nsIDOMEventListener {
void RegisterListenersFor(EventTarget* aRoot);
void UnregisterListenersFor(EventTarget* aRoot);
void AddObservers();
void RemoveObservers();
private:
explicit JSWindowActorProtocol(const nsAString& aName) : mName(aName) {}
@ -133,7 +138,7 @@ class JSWindowActorProtocol final : public nsIDOMEventListener {
ChildSide mChild;
};
NS_IMPL_ISUPPORTS(JSWindowActorProtocol, nsIDOMEventListener);
NS_IMPL_ISUPPORTS(JSWindowActorProtocol, nsIObserver, nsIDOMEventListener);
/* static */ already_AddRefed<JSWindowActorProtocol>
JSWindowActorProtocol::FromIPC(const JSWindowActorInfo& aInfo) {
@ -154,6 +159,7 @@ JSWindowActorProtocol::FromIPC(const JSWindowActorInfo& aInfo) {
}
}
proto->mChild.mObservers = aInfo.observers();
return proto.forget();
}
@ -177,6 +183,7 @@ JSWindowActorInfo JSWindowActorProtocol::ToIPC() {
}
}
info.observers() = mChild.mObservers;
return info;
}
@ -219,6 +226,10 @@ JSWindowActorProtocol::FromWebIDLOptions(const nsAString& aName,
}
}
if (aOptions.mChild.mObservers.WasPassed()) {
proto->mChild.mObservers = aOptions.mChild.mObservers.Value();
}
return proto.forget();
}
@ -257,6 +268,67 @@ NS_IMETHODIMP JSWindowActorProtocol::HandleEvent(Event* aEvent) {
return CallJSActorMethod(actor, "handleEvent", aEvent, &dummy);
}
NS_IMETHODIMP JSWindowActorProtocol::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData) {
nsCOMPtr<nsPIDOMWindowInner> inner = do_QueryInterface(aSubject);
if (NS_WARN_IF(!inner)) {
return NS_ERROR_FAILURE;
}
RefPtr<WindowGlobalChild> wgc = inner->GetWindowGlobalChild();
if (NS_WARN_IF(!wgc)) {
return NS_ERROR_FAILURE;
}
// Ensure our actor is present.
ErrorResult error;
RefPtr<JSWindowActorChild> actor = wgc->GetActor(mName, error);
if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult();
}
// Get the wrapper for our actor. If we don't have a wrapper, the target
// method won't be defined on it. so there's no reason to continue.
JS::Rooted<JSObject*> obj(RootingCx(), actor->GetWrapper());
if (NS_WARN_IF(!obj)) {
return NS_ERROR_NOT_IMPLEMENTED;
}
// Enter the realm of our actor object to begin running script.
AutoEntryScript aes(obj, "JSWindowActorProtocol::Observe");
JSContext* cx = aes.cx();
JSAutoRealm ar(cx, obj);
JS::AutoValueArray<3> argv(cx);
if (NS_WARN_IF(
!ToJSValue(cx, aSubject, argv[0]) ||
!NonVoidByteStringToJsval(cx, nsDependentCString(aTopic), argv[1]))) {
JS_ClearPendingException(cx);
return NS_ERROR_FAILURE;
}
// aData is an optional parameter.
if (aData) {
if (NS_WARN_IF(!ToJSValue(cx, nsDependentString(aData), argv[2]))) {
JS_ClearPendingException(cx);
return NS_ERROR_FAILURE;
}
} else {
argv[2].setNull();
}
// Call the "observe" method on our actor.
JS::Rooted<JS::Value> dummy(cx);
if (NS_WARN_IF(!JS_CallFunctionName(cx, obj, "observe",
JS::HandleValueArray(argv), &dummy))) {
JS_ClearPendingException(cx);
return NS_ERROR_FAILURE;
}
return NS_OK;
}
void JSWindowActorProtocol::RegisterListenersFor(EventTarget* aRoot) {
EventListenerManager* elm = aRoot->GetOrCreateListenerManager();
@ -275,6 +347,24 @@ void JSWindowActorProtocol::UnregisterListenersFor(EventTarget* aRoot) {
}
}
void JSWindowActorProtocol::AddObservers() {
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
for (auto& topic : mChild.mObservers) {
// This makes the observer service hold an owning reference to the
// JSWindowActorProtocol. The JSWindowActorProtocol objects will be living
// for the full lifetime of the content process, thus the extra strong
// referencec doesn't have a negative impact.
os->AddObserver(this, topic.get(), false);
}
}
void JSWindowActorProtocol::RemoveObservers() {
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
for (auto& topic : mChild.mObservers) {
os->RemoveObserver(this, topic.get());
}
}
JSWindowActorService::JSWindowActorService() { MOZ_ASSERT(NS_IsMainThread()); }
JSWindowActorService::~JSWindowActorService() { MOZ_ASSERT(NS_IsMainThread()); }
@ -323,6 +413,9 @@ void JSWindowActorService::RegisterWindowActor(
for (EventTarget* root : mRoots) {
proto->RegisterListenersFor(root);
}
// Add observers to the protocol.
proto->AddObservers();
}
void JSWindowActorService::UnregisterWindowActor(const nsAString& aName) {
@ -342,6 +435,9 @@ void JSWindowActorService::UnregisterWindowActor(const nsAString& aName) {
for (EventTarget* root : mRoots) {
proto->UnregisterListenersFor(root);
}
// Remove observers for this actor from observer serivce.
proto->RemoveObservers();
}
}
@ -360,6 +456,9 @@ void JSWindowActorService::LoadJSWindowActorInfos(
for (EventTarget* root : mRoots) {
proto->RegisterListenersFor(root);
}
// Add observers for each actor.
proto->AddObservers();
}
}

Просмотреть файл

@ -243,6 +243,7 @@ struct JSWindowActorInfo
nsCString url;
JSWindowActorEventDecl[] events;
nsCString[] observers;
};
struct GMPAPITags