gecko/accessible/ipc/DocAccessibleParent.h
Trevor Saunders 7713d92e5d bug 1170595 - switch to sending __delete__ from the parent instead of the child r=davidb, smaug
After the child sends the __delete__ message to the parent there is a period of
time in which the actor is registered, but the parent hasn't yet processed the
__delete__ message.  During that time the parent can still try and send
messages to the child, but that will crash the child process.  Fix this race by
making the child send a shutdown message to the parent, and have the parent
send __delete__ when it handles that message.
2015-06-05 16:10:34 -04:00

161 lines
4.7 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=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/. */
#ifndef mozilla_a11y_DocAccessibleParent_h
#define mozilla_a11y_DocAccessibleParent_h
#include "nsAccessibilityService.h"
#include "ProxyAccessible.h"
#include "mozilla/a11y/PDocAccessibleParent.h"
#include "nsClassHashtable.h"
#include "nsHashKeys.h"
#include "nsISupportsImpl.h"
namespace mozilla {
namespace a11y {
/*
* These objects live in the main process and comunicate with and represent
* an accessible document in a content process.
*/
class DocAccessibleParent : public ProxyAccessible,
public PDocAccessibleParent
{
public:
DocAccessibleParent() :
ProxyAccessible(this), mParentDoc(nullptr), mShutdown(false)
{ MOZ_COUNT_CTOR_INHERITED(DocAccessibleParent, ProxyAccessible); }
~DocAccessibleParent()
{
MOZ_COUNT_DTOR_INHERITED(DocAccessibleParent, ProxyAccessible);
MOZ_ASSERT(mChildDocs.Length() == 0);
MOZ_ASSERT(!ParentDoc());
}
/*
* Called when a message from a document in a child process notifies the main
* process it is firing an event.
*/
virtual bool RecvEvent(const uint64_t& aID, const uint32_t& aType)
override;
virtual bool RecvShowEvent(const ShowEventData& aData) override;
virtual bool RecvHideEvent(const uint64_t& aRootID) override;
virtual bool RecvStateChangeEvent(const uint64_t& aID,
const uint64_t& aState,
const bool& aEnabled) override final;
virtual bool RecvCaretMoveEvent(const uint64_t& aID, const int32_t& aOffset)
override final;
virtual bool RecvBindChildDoc(PDocAccessibleParent* aChildDoc, const uint64_t& aID) override;
void Unbind()
{
mParent = nullptr;
ParentDoc()->mChildDocs.RemoveElement(this);
mParentDoc = nullptr;
}
virtual bool RecvShutdown() override;
void Destroy();
virtual void ActorDestroy(ActorDestroyReason aWhy) override
{
if (!mShutdown)
Destroy();
}
/*
* Return the main processes representation of the parent document (if any)
* of the document this object represents.
*/
DocAccessibleParent* ParentDoc() const { return mParentDoc; }
/*
* Called when a document in a content process notifies the main process of a
* new child document.
*/
bool AddChildDoc(DocAccessibleParent* aChildDoc, uint64_t aParentID,
bool aCreating = true);
/*
* Called when the document in the content process this object represents
* notifies the main process a child document has been removed.
*/
void RemoveChildDoc(DocAccessibleParent* aChildDoc)
{
aChildDoc->Parent()->SetChildDoc(nullptr);
mChildDocs.RemoveElement(aChildDoc);
aChildDoc->mParentDoc = nullptr;
MOZ_ASSERT(aChildDoc->mChildDocs.Length() == 0);
}
void RemoveAccessible(ProxyAccessible* aAccessible)
{
MOZ_ASSERT(mAccessibles.GetEntry(aAccessible->ID()));
mAccessibles.RemoveEntry(aAccessible->ID());
}
/**
* Return the accessible for given id.
*/
ProxyAccessible* GetAccessible(uintptr_t aID)
{
if (!aID)
return this;
ProxyEntry* e = mAccessibles.GetEntry(aID);
return e ? e->mProxy : nullptr;
}
const ProxyAccessible* GetAccessible(uintptr_t aID) const
{ return const_cast<DocAccessibleParent*>(this)->GetAccessible(aID); }
private:
class ProxyEntry : public PLDHashEntryHdr
{
public:
explicit ProxyEntry(const void*) : mProxy(nullptr) {}
ProxyEntry(ProxyEntry&& aOther) :
mProxy(aOther.mProxy) { aOther.mProxy = nullptr; }
~ProxyEntry() { delete mProxy; }
typedef uint64_t KeyType;
typedef const void* KeyTypePointer;
bool KeyEquals(const void* aKey) const
{ return mProxy->ID() == (uint64_t)aKey; }
static const void* KeyToPointer(uint64_t aKey) { return (void*)aKey; }
static PLDHashNumber HashKey(const void* aKey) { return (uint64_t)aKey; }
enum { ALLOW_MEMMOVE = true };
ProxyAccessible* mProxy;
};
uint32_t AddSubtree(ProxyAccessible* aParent,
const nsTArray<AccessibleData>& aNewTree, uint32_t aIdx,
uint32_t aIdxInParent);
static PLDHashOperator ShutdownAccessibles(ProxyEntry* entry, void* unused);
nsTArray<DocAccessibleParent*> mChildDocs;
DocAccessibleParent* mParentDoc;
/*
* Conceptually this is a map from IDs to proxies, but we store the ID in the
* proxy object so we can't use a real map.
*/
nsTHashtable<ProxyEntry> mAccessibles;
bool mShutdown;
};
}
}
#endif