--- a/accessible/atk/AccessibleWrap.cpp
+++ b/accessible/atk/AccessibleWrap.cpp
@@ -7,24 +7,26 @@
#include "AccessibleWrap.h"
#include "Accessible-inl.h"
#include "ApplicationAccessibleWrap.h"
#include "InterfaceInitFuncs.h"
#include "nsAccUtils.h"
#include "nsIAccessibleRelation.h"
#include "nsIAccessibleTable.h"
+#include "ProxyAccessible.h"
#include "RootAccessible.h"
#include "nsIAccessibleValue.h"
#include "nsMai.h"
#include "nsMaiHyperlink.h"
#include "nsString.h"
#include "nsAutoPtr.h"
#include "prprf.h"
#include "nsStateMap.h"
+#include "mozilla/a11y/Platform.h"
#include "Relation.h"
#include "RootAccessible.h"
#include "States.h"
#include "nsISimpleEnumerator.h"
#include "mozilla/ArrayUtils.h"
#include "nsXPCOMStrings.h"
#include "nsComponentManagerUtils.h"
@@ -128,19 +130,23 @@ static const GInterfaceInfo atk_if_infos
*/
struct MaiAtkObject
{
AtkObject parent;
/*
* The AccessibleWrap whose properties and features are exported
* via this object instance.
*/
- AccessibleWrap* accWrap;
+ uintptr_t accWrap;
};
+// This is or'd with the pointer in MaiAtkObject::accWrap if the wrap-ee is a
+// proxy.
+static const uintptr_t IS_PROXY = 1;
+
struct MaiAtkObjectClass
{
AtkObjectClass parent_class;
};
static guint mai_atk_object_signals [LAST_SIGNAL] = { 0, };
static void MaybeFireNameChange(AtkObject* aAtkObj, const nsString& aNewName);
@@ -243,17 +249,17 @@ AccessibleWrap::~AccessibleWrap()
NS_ASSERTION(!mAtkObject, "ShutdownAtkObject() is not called");
}
void
AccessibleWrap::ShutdownAtkObject()
{
if (mAtkObject) {
if (IS_MAI_OBJECT(mAtkObject)) {
- MAI_ATK_OBJECT(mAtkObject)->accWrap = nullptr;
+ MAI_ATK_OBJECT(mAtkObject)->accWrap = 0;
}
SetMaiHyperlink(nullptr);
g_object_unref(mAtkObject);
mAtkObject = nullptr;
}
}
void
@@ -577,26 +583,25 @@ initializeCB(AtkObject *aAtkObj, gpointe
/* AtkObjectClass has not a "initialize" function now,
* maybe it has later
*/
if (ATK_OBJECT_CLASS(parent_class)->initialize)
ATK_OBJECT_CLASS(parent_class)->initialize(aAtkObj, aData);
/* initialize object */
- MAI_ATK_OBJECT(aAtkObj)->accWrap =
- static_cast<AccessibleWrap*>(aData);
+ MAI_ATK_OBJECT(aAtkObj)->accWrap = reinterpret_cast<uintptr_t>(aData);
}
void
finalizeCB(GObject *aObj)
{
if (!IS_MAI_OBJECT(aObj))
return;
- NS_ASSERTION(MAI_ATK_OBJECT(aObj)->accWrap == nullptr, "AccWrap NOT null");
+ NS_ASSERTION(MAI_ATK_OBJECT(aObj)->accWrap == 0, "AccWrap NOT null");
// call parent finalize function
// finalize of GObjectClass will unref the accessible parent if has
if (G_OBJECT_CLASS (parent_class)->finalize)
G_OBJECT_CLASS (parent_class)->finalize(aObj);
}
const gchar*
@@ -658,35 +663,43 @@ getDescriptionCB(AtkObject *aAtkObj)
NS_ConvertUTF16toUTF8(uniDesc).get());
return aAtkObj->description;
}
AtkRole
getRoleCB(AtkObject *aAtkObj)
{
- AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
- if (!accWrap)
- return ATK_ROLE_INVALID;
+ if (aAtkObj->role != ATK_ROLE_INVALID)
+ return aAtkObj->role;
+ AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
+ a11y::role role;
+ if (!accWrap) {
+ ProxyAccessible* proxy = GetProxy(aAtkObj);
+ if (!proxy)
+ return ATK_ROLE_INVALID;
+
+ role = proxy->Role();
+ } else {
#ifdef DEBUG
- NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(accWrap),
- "Does not support nsIAccessibleText when it should");
+ NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(accWrap),
+ "Does not support nsIAccessibleText when it should");
#endif
- if (aAtkObj->role != ATK_ROLE_INVALID)
- return aAtkObj->role;
+ role = accWrap->Role();
+ }
#define ROLE(geckoRole, stringRole, atkRole, macRole, \
msaaRole, ia2Role, nameRule) \
case roles::geckoRole: \
aAtkObj->role = atkRole; \
break;
- switch (accWrap->Role()) {
+ switch (role) {
#include "RoleMap.h"
default:
MOZ_CRASH("Unknown role.");
};
#undef ROLE
if (aAtkObj->role == ATK_ROLE_LIST_BOX && !IsAtkVersionAtLeast(2, 1))
@@ -941,31 +954,80 @@ refRelationSetCB(AtkObject *aAtkObj)
}
// Check if aAtkObj is a valid MaiAtkObject, and return the AccessibleWrap
// for it.
AccessibleWrap*
GetAccessibleWrap(AtkObject* aAtkObj)
{
NS_ENSURE_TRUE(IS_MAI_OBJECT(aAtkObj), nullptr);
- AccessibleWrap* accWrap = MAI_ATK_OBJECT(aAtkObj)->accWrap;
+
+ // Make sure its native is an AccessibleWrap not a proxy.
+ if (MAI_ATK_OBJECT(aAtkObj)->accWrap & IS_PROXY)
+ return nullptr;
+
+ AccessibleWrap* accWrap =
+ reinterpret_cast<AccessibleWrap*>(MAI_ATK_OBJECT(aAtkObj)->accWrap);
// Check if the accessible was deconstructed.
if (!accWrap)
return nullptr;
NS_ENSURE_TRUE(accWrap->GetAtkObject() == aAtkObj, nullptr);
AccessibleWrap* appAccWrap = ApplicationAcc();
if (appAccWrap != accWrap && !accWrap->IsValidObject())
return nullptr;
return accWrap;
}
+ProxyAccessible*
+GetProxy(AtkObject* aObj)
+{
+ if (!aObj || !(MAI_ATK_OBJECT(aObj)->accWrap & IS_PROXY))
+ return nullptr;
+
+ return reinterpret_cast<ProxyAccessible*>(MAI_ATK_OBJECT(aObj)->accWrap
+ & ~IS_PROXY);
+}
+
+static uint16_t
+GetInterfacesForProxy(ProxyAccessible* aProxy)
+{
+ return MAI_INTERFACE_COMPONENT;
+}
+
+void
+a11y::ProxyCreated(ProxyAccessible* aProxy)
+{
+ GType type = GetMaiAtkType(GetInterfacesForProxy(aProxy));
+ NS_ASSERTION(type, "why don't we have a type!");
+
+ AtkObject* obj =
+ reinterpret_cast<AtkObject *>
+ (g_object_new(type, nullptr));
+ if (!obj)
+ return;
+
+ atk_object_initialize(obj, aProxy);
+ obj->role = ATK_ROLE_INVALID;
+ obj->layer = ATK_LAYER_INVALID;
+ aProxy->SetWrapper(reinterpret_cast<uintptr_t>(obj) | IS_PROXY);
+}
+
+void
+a11y::ProxyDestroyed(ProxyAccessible* aProxy)
+{
+ auto obj = reinterpret_cast<MaiAtkObject*>(aProxy->GetWrapper() & ~IS_PROXY);
+ obj->accWrap = 0;
+ g_object_unref(obj);
+ aProxy->SetWrapper(0);
+}
+
nsresult
AccessibleWrap::HandleAccEvent(AccEvent* aEvent)
{
nsresult rv = Accessible::HandleAccEvent(aEvent);
NS_ENSURE_SUCCESS(rv, rv);
Accessible* accessible = aEvent->GetAccessible();
NS_ENSURE_TRUE(accessible, NS_ERROR_FAILURE);
--- a/accessible/atk/AccessibleWrap.h
+++ b/accessible/atk/AccessibleWrap.h
@@ -92,15 +92,15 @@ private:
enum EAvailableAtkSignals {
eUnknown,
eHaveNewAtkTextSignals,
eNoNewAtkSignals
};
static EAvailableAtkSignals gAvailableAtkSignals;
- uint16_t CreateMaiInterfaces(void);
+ uint16_t CreateMaiInterfaces();
};
} // namespace a11y
} // namespace mozilla
#endif /* __NS_ACCESSIBLE_WRAP_H__ */
--- a/accessible/atk/moz.build
+++ b/accessible/atk/moz.build
@@ -30,16 +30,17 @@ SOURCES += [
'RootAccessibleWrap.cpp',
'UtilInterface.cpp',
]
LOCAL_INCLUDES += [
'/accessible/base',
'/accessible/generic',
'/accessible/html',
+ '/accessible/ipc',
'/accessible/xpcom',
'/accessible/xul',
'/other-licenses/atk-1.0',
]
FINAL_LIBRARY = 'xul'
if CONFIG['MOZ_ENABLE_GTK']:
--- a/accessible/atk/nsMai.h
+++ b/accessible/atk/nsMai.h
@@ -8,32 +8,39 @@
#define __NS_MAI_H__
#include <atk/atk.h>
#include <glib.h>
#include <glib-object.h>
#include "AccessibleWrap.h"
+namespace mozilla {
+namespace a11y {
+class ProxyAccessible;
+}
+}
+
#define MAI_TYPE_ATK_OBJECT (mai_atk_object_get_type ())
#define MAI_ATK_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
MAI_TYPE_ATK_OBJECT, MaiAtkObject))
#define MAI_ATK_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \
MAI_TYPE_ATK_OBJECT, \
MaiAtkObjectClass))
#define IS_MAI_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
MAI_TYPE_ATK_OBJECT))
#define IS_MAI_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
MAI_TYPE_ATK_OBJECT))
#define MAI_ATK_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
MAI_TYPE_ATK_OBJECT, \
MaiAtkObjectClass))
GType mai_atk_object_get_type(void);
GType mai_util_get_type();
mozilla::a11y::AccessibleWrap* GetAccessibleWrap(AtkObject* aAtkObj);
+mozilla::a11y::ProxyAccessible* GetProxy(AtkObject* aAtkObj);
extern int atkMajorVersion, atkMinorVersion;
/**
* Return true if the loaded version of libatk-1.0.so is at least
* aMajor.aMinor.0.
*/
static inline bool
--- a/accessible/base/AccEvent.h
+++ b/accessible/base/AccEvent.h
@@ -227,16 +227,18 @@ public:
{
return AccEvent::GetEventGroups() | (1U << eMutationEvent);
}
// MutationEvent
bool IsShow() const { return mEventType == nsIAccessibleEvent::EVENT_SHOW; }
bool IsHide() const { return mEventType == nsIAccessibleEvent::EVENT_HIDE; }
+ Accessible* Parent() const { return mParent; }
+
protected:
nsCOMPtr<nsINode> mNode;
nsRefPtr<Accessible> mParent;
nsRefPtr<AccTextChangeEvent> mTextChangeEvent;
friend class EventQueue;
};
--- a/accessible/base/DocManager.cpp
+++ b/accessible/base/DocManager.cpp
@@ -3,16 +3,17 @@
* 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 "DocManager.h"
#include "ApplicationAccessible.h"
#include "ARIAMap.h"
#include "DocAccessible-inl.h"
+#include "DocAccessibleChild.h"
#include "nsAccessibilityService.h"
#include "RootAccessibleWrap.h"
#ifdef A11Y_LOG
#include "Logging.h"
#endif
#include "mozilla/EventListenerManager.h"
@@ -22,16 +23,18 @@
#include "nsIChannel.h"
#include "nsIDOMDocument.h"
#include "nsIDOMWindow.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIWebNavigation.h"
#include "nsServiceManagerUtils.h"
#include "nsIWebProgress.h"
#include "nsCoreUtils.h"
+#include "nsXULAppAPI.h"
+#include "mozilla/dom/ContentChild.h"
using namespace mozilla;
using namespace mozilla::a11y;
using namespace mozilla::dom;
////////////////////////////////////////////////////////////////////////////////
// DocManager
////////////////////////////////////////////////////////////////////////////////
@@ -413,16 +416,22 @@ DocManager::CreateDocOrRootAccessible(ns
// the tree. The reorder event is delivered after the document tree is
// constructed because event processing and tree construction are done by
// the same document.
// Note: don't use AccReorderEvent to avoid coalsecense and special reorder
// events processing.
docAcc->FireDelayedEvent(nsIAccessibleEvent::EVENT_REORDER,
ApplicationAcc());
+ if (XRE_GetProcessType() != GeckoProcessType_Default) {
+ DocAccessibleChild* ipcDoc = new DocAccessibleChild(docAcc);
+ docAcc->SetIPCDoc(ipcDoc);
+ auto contentChild = dom::ContentChild::GetSingleton();
+ contentChild->SendPDocAccessibleConstructor(ipcDoc, nullptr, 0);
+ }
} else {
parentDocAcc->BindChildDocument(docAcc);
}
#ifdef A11Y_LOG
if (logging::IsEnabled(logging::eDocCreate)) {
logging::DocCreate("document creation finished", aDocument);
logging::Stack();
--- a/accessible/base/DocManager.h
+++ b/accessible/base/DocManager.h
@@ -12,16 +12,17 @@
#include "nsWeakReference.h"
#include "nsIPresShell.h"
namespace mozilla {
namespace a11y {
class Accessible;
class DocAccessible;
+class DocAccessibleParent;
/**
* Manage the document accessible life cycle.
*/
class DocManager : public nsIWebProgressListener,
public nsIDOMEventListener,
public nsSupportsWeakReference
{
@@ -60,16 +61,35 @@ public:
* Called by document accessible when it gets shutdown.
*/
inline void NotifyOfDocumentShutdown(nsIDocument* aDocument)
{
mDocAccessibleCache.Remove(aDocument);
RemoveListeners(aDocument);
}
+ /*
+ * Notification that a top level document in a content process has gone away.
+ */
+ void RemoteDocShutdown(DocAccessibleParent* aDoc)
+ {
+ DebugOnly<bool> result = mRemoteDocuments.RemoveElement(aDoc);
+ MOZ_ASSERT(result, "Why didn't we find the document!");
+ }
+
+ /*
+ * Notify of a new top level document in a content process.
+ */
+ void RemoteDocAdded(DocAccessibleParent* aDoc)
+ {
+ MOZ_ASSERT(!mRemoteDocuments.Contains(aDoc),
+ "How did we already have the doc!");
+ mRemoteDocuments.AppendElement(aDoc);
+ }
+
#ifdef DEBUG
bool IsProcessingRefreshDriverNotification() const;
#endif
protected:
DocManager();
virtual ~DocManager() { }
@@ -139,16 +159,21 @@ private:
#ifdef DEBUG
static PLDHashOperator
SearchIfDocIsRefreshing(const nsIDocument* aKey,
DocAccessible* aDocAccessible, void* aUserArg);
#endif
DocAccessibleHashtable mDocAccessibleCache;
+
+ /*
+ * The list of remote top level documents.
+ */
+ nsTArray<DocAccessibleParent*> mRemoteDocuments;
};
/**
* Return the existing document accessible for the document if any.
* Note this returns the doc accessible for the primary pres shell if there is
* more than one.
*/
inline DocAccessible*
--- a/accessible/base/EventQueue.cpp
+++ b/accessible/base/EventQueue.cpp
@@ -3,16 +3,17 @@
* 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 "EventQueue.h"
#include "Accessible-inl.h"
#include "nsEventShell.h"
#include "DocAccessible.h"
+#include "DocAccessibleChild.h"
#include "nsAccessibilityService.h"
#include "nsTextEquivUtils.h"
#ifdef A11Y_LOG
#include "Logging.h"
#endif
using namespace mozilla;
using namespace mozilla::a11y;
@@ -550,10 +551,20 @@ EventQueue::ProcessEventQueue()
}
}
if (event->mEventType == nsIAccessibleEvent::EVENT_HIDE)
mDocument->ShutdownChildrenInSubtree(event->mAccessible);
if (!mDocument)
return;
+
+ if (XRE_GetProcessType() != GeckoProcessType_Default) {
+ DocAccessibleChild* ipcDoc = mDocument->IPCDoc();
+ if (event->mEventType == nsIAccessibleEvent::EVENT_SHOW)
+ ipcDoc->ShowEvent(downcast_accEvent(event));
+ else if (event->mEventType == nsIAccessibleEvent::EVENT_HIDE)
+ ipcDoc->SendHideEvent(reinterpret_cast<uintptr_t>(event->GetAccessible()));
+ else
+ ipcDoc->SendEvent(event->GetEventType());
+ }
}
}
--- a/accessible/base/NotificationController.cpp
+++ b/accessible/base/NotificationController.cpp
@@ -1,19 +1,21 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "NotificationController.h"
#include "DocAccessible-inl.h"
+#include "DocAccessibleChild.h"
#include "TextLeafAccessible.h"
#include "TextUpdater.h"
+#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/Element.h"
#include "mozilla/Telemetry.h"
using namespace mozilla;
using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
// NotificationCollector
@@ -212,18 +214,29 @@ NotificationController::WillRefresh(mozi
if (childDoc->IsDefunct())
continue;
nsIContent* ownerContent = mDocument->DocumentNode()->
FindContentForSubDocument(childDoc->DocumentNode());
if (ownerContent) {
Accessible* outerDocAcc = mDocument->GetAccessible(ownerContent);
if (outerDocAcc && outerDocAcc->AppendChild(childDoc)) {
- if (mDocument->AppendChildDocument(childDoc))
+ if (mDocument->AppendChildDocument(childDoc)) {
+ if (XRE_GetProcessType() != GeckoProcessType_Default) {
+ DocAccessibleChild* ipcDoc = new DocAccessibleChild(childDoc);
+ childDoc->SetIPCDoc(ipcDoc);
+ auto contentChild = dom::ContentChild::GetSingleton();
+ DocAccessibleChild* parentIPCDoc = mDocument->IPCDoc();
+ uint64_t id = reinterpret_cast<uintptr_t>(outerDocAcc->UniqueID());
+ contentChild->SendPDocAccessibleConstructor(ipcDoc, parentIPCDoc,
+ id);
+ }
+
continue;
+ }
outerDocAcc->RemoveChild(childDoc);
}
// Failed to bind the child document, destroy it.
childDoc->Shutdown();
}
}
--- a/accessible/base/Platform.h
+++ b/accessible/base/Platform.h
@@ -2,16 +2,18 @@
/* 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/. */
namespace mozilla {
namespace a11y {
+class ProxyAccessible;
+
enum EPlatformDisabledState {
ePlatformIsForceEnabled = -1,
ePlatformIsEnabled = 0,
ePlatformIsDisabled = 1
};
/**
* Return the platform disabled state.
@@ -42,11 +44,22 @@ bool ShouldA11yBeEnabled();
void PlatformInit();
/**
* Shutdown platform accessibility.
* Note this is called before internal accessibility support is shutdown.
*/
void PlatformShutdown();
+/**
+ * called when a new ProxyAccessible is created, so the platform may setup a
+ * wrapper for it, or take other action.
+ */
+void ProxyCreated(ProxyAccessible*);
+
+/**
+ * Called just before a ProxyAccessible is destroyed so its wrapper can be
+ * disposed of and other action taken.
+ */
+void ProxyDestroyed(ProxyAccessible*);
} // namespace a11y
} // namespace mozilla
--- a/accessible/base/Role.h
+++ b/accessible/base/Role.h
@@ -778,17 +778,19 @@ enum Role {
/**
* Represent a definition in a definition list (dd in HTML)
*/
DEFINITION = 128,
/**
* Represent a keyboard or keypad key (ARIA role "key").
*/
- KEY = 129
+ KEY = 129,
+
+ LAST_ROLE = KEY
};
} // namespace role
typedef enum mozilla::a11y::roles::Role role;
} // namespace a11y
} // namespace mozilla
--- a/accessible/base/moz.build
+++ b/accessible/base/moz.build
@@ -55,16 +55,17 @@ UNIFIED_SOURCES += [
if CONFIG['A11Y_LOG']:
UNIFIED_SOURCES += [
'Logging.cpp',
]
LOCAL_INCLUDES += [
'/accessible/generic',
'/accessible/html',
+ '/accessible/ipc',
'/accessible/xpcom',
'/accessible/xul',
'/dom/xbl',
'/ipc/chromium/src',
'/layout/generic',
'/layout/style',
'/layout/svg',
'/layout/xul',
@@ -88,8 +89,10 @@ else:
LOCAL_INCLUDES += [
'/accessible/other',
]
FINAL_LIBRARY = 'xul'
if CONFIG['MOZ_ENABLE_GTK']:
CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
+
+include('/ipc/chromium/chromium-config.mozbuild')
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -1,16 +1,17 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "Accessible-inl.h"
#include "AccIterator.h"
#include "DocAccessible-inl.h"
+#include "DocAccessibleChild.h"
#include "HTMLImageMapAccessible.h"
#include "nsAccCache.h"
#include "nsAccessiblePivot.h"
#include "nsAccUtils.h"
#include "nsEventShell.h"
#include "nsTextEquivUtils.h"
#include "Role.h"
#include "RootAccessible.h"
@@ -78,17 +79,17 @@ DocAccessible::
HyperTextAccessibleWrap(aRootContent, this), xpcAccessibleDocument(),
// XXX aaronl should we use an algorithm for the initial cache size?
mAccessibleCache(kDefaultCacheLength),
mNodeToAccessibleMap(kDefaultCacheLength),
mDocumentNode(aDocument),
mScrollPositionChangedTicks(0),
mLoadState(eTreeConstructionPending), mDocFlags(0), mLoadEventType(0),
mVirtualCursor(nullptr),
- mPresShell(aPresShell)
+ mPresShell(aPresShell), mIPCDoc(nullptr)
{
mGenericTypes |= eDocument;
mStateFlags |= eNotNodeMapEntry;
MOZ_ASSERT(mPresShell, "should have been given a pres shell");
mPresShell->SetDocAccessible(this);
// If this is a XUL Document, it should not implement nsHyperText
@@ -468,16 +469,22 @@ DocAccessible::Shutdown()
// Walk the array backwards because child documents remove themselves from the
// array as they are shutdown.
int32_t childDocCount = mChildDocuments.Length();
for (int32_t idx = childDocCount - 1; idx >= 0; idx--)
mChildDocuments[idx]->Shutdown();
mChildDocuments.Clear();
+ // XXX thinking about ordering?
+ if (XRE_GetProcessType() != GeckoProcessType_Default) {
+ DocAccessibleChild::Send__delete__(mIPCDoc);
+ MOZ_ASSERT(!mIPCDoc);
+ }
+
if (mVirtualCursor) {
mVirtualCursor->RemoveObserver(this);
mVirtualCursor = nullptr;
}
mPresShell->SetDocAccessible(nullptr);
mPresShell = nullptr; // Avoid reentrancy
@@ -1441,16 +1448,23 @@ DocAccessible::DoInitialUpdate()
// Fire reorder event after the document tree is constructed. Note, since
// this reorder event is processed by parent document then events targeted to
// this document may be fired prior to this reorder event. If this is
// a problem then consider to keep event processing per tab document.
if (!IsRoot()) {
nsRefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(Parent());
ParentDocument()->FireDelayedEvent(reorderEvent);
}
+
+ uint32_t childCount = ChildCount();
+ for (uint32_t i = 0; i < childCount; i++) {
+ Accessible* child = GetChildAt(i);
+ nsRefPtr<AccShowEvent> event = new AccShowEvent(child, child->GetContent());
+ FireDelayedEvent(event);
+ }
}
void
DocAccessible::ProcessLoad()
{
mLoadState |= eCompletelyLoaded;
#ifdef A11Y_LOG
--- a/accessible/generic/DocAccessible.h
+++ b/accessible/generic/DocAccessible.h
@@ -28,16 +28,17 @@ class nsIScrollableView;
const uint32_t kDefaultCacheLength = 128;
namespace mozilla {
namespace a11y {
class DocManager;
class NotificationController;
+class DocAccessibleChild;
class RelatedAccIterator;
template<class Class, class Arg>
class TNotification;
class DocAccessible : public HyperTextAccessibleWrap,
public xpcAccessibleDocument,
public nsIDocumentObserver,
public nsIObserver,
@@ -515,16 +516,30 @@ protected:
* Rules: The root chrome document accessible is never an event target
* (for example, Firefox UI window). If the sub document is loaded within its
* parent document then the parent document is a target only (aka events
* coalescence).
*/
bool IsLoadEventTarget() const;
/**
+ * If this document is in a content process return the object responsible for
+ * communicating with the main process for it.
+ */
+ DocAccessibleChild* IPCDoc() const { return mIPCDoc; }
+
+ /*
+ * Set the object responsible for communicating with the main process on
+ * behalf of this document.
+ */
+ void SetIPCDoc(DocAccessibleChild* aIPCDoc) { mIPCDoc = aIPCDoc; }
+
+ friend class DocAccessibleChild;
+
+ /**
* Used to fire scrolling end event after page scroll.
*
* @param aTimer [in] the timer object
* @param aClosure [in] the document accessible where scrolling happens
*/
static void ScrollTimerCallback(nsITimer* aTimer, void* aClosure);
protected:
@@ -637,16 +652,19 @@ protected:
*/
nsRefPtr<NotificationController> mNotificationController;
friend class EventQueue;
friend class NotificationController;
private:
nsIPresShell* mPresShell;
+
+ // Exclusively owned by IPDL so don't manually delete it!
+ DocAccessibleChild* mIPCDoc;
};
inline DocAccessible*
Accessible::AsDoc()
{
return IsDoc() ? static_cast<DocAccessible*>(this) : nullptr;
}
--- a/accessible/generic/moz.build
+++ b/accessible/generic/moz.build
@@ -23,16 +23,17 @@ UNIFIED_SOURCES += [
'RootAccessible.cpp',
'TableCellAccessible.cpp',
'TextLeafAccessible.cpp',
]
LOCAL_INCLUDES += [
'/accessible/base',
'/accessible/html',
+ '/accessible/ipc',
'/accessible/xpcom',
'/accessible/xul',
'/content/base/src',
'/layout/generic',
'/layout/xul',
]
if CONFIG['MOZ_ENABLE_GTK']:
@@ -49,8 +50,10 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'co
'/accessible/mac',
]
else:
LOCAL_INCLUDES += [
'/accessible/other',
]
FINAL_LIBRARY = 'xul'
+
+include('/ipc/chromium/chromium-config.mozbuild')
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/DocAccessibleChild.cpp
@@ -0,0 +1,40 @@
+/* -*- 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/. */
+
+#include "DocAccessibleChild.h"
+
+#include "Accessible-inl.h"
+
+namespace mozilla {
+namespace a11y {
+
+void
+SerializeTree(Accessible* aRoot, nsTArray<AccessibleData>& aTree)
+{
+ uint64_t id = reinterpret_cast<uint64_t>(aRoot->UniqueID());
+ uint32_t role = aRoot->Role();
+ uint32_t childCount = aRoot->ChildCount();
+
+ nsString name;
+ aRoot->Name(name);
+ aTree.AppendElement(AccessibleData(id, role, childCount, name));
+ for (uint32_t i = 0; i < childCount; i++)
+ SerializeTree(aRoot->GetChildAt(i), aTree);
+}
+
+void
+DocAccessibleChild::ShowEvent(AccShowEvent* aShowEvent)
+{
+ Accessible* parent = aShowEvent->Parent();
+ uint64_t parentID = parent->IsDoc() ? 0 : reinterpret_cast<uint64_t>(parent->UniqueID());
+ uint32_t idxInParent = aShowEvent->GetAccessible()->IndexInParent();
+ nsTArray<AccessibleData> shownTree;
+ ShowEventData data(parentID, idxInParent, shownTree);
+ SerializeTree(aShowEvent->GetAccessible(), data.NewTree());
+ SendShowEvent(data);
+}
+}
+}
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/DocAccessibleChild.h
@@ -0,0 +1,43 @@
+/* -*- 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_DocAccessibleChild_h
+#define mozilla_a11y_DocAccessibleChild_h
+
+#include "mozilla/a11y/DocAccessible.h"
+#include "mozilla/a11y/PDocAccessibleChild.h"
+#include "nsISupportsImpl.h"
+
+namespace mozilla {
+namespace a11y {
+class AccShowEvent;
+
+ /*
+ * These objects handle content side communication for an accessible document,
+ * and their lifetime is the same as the document they represent.
+ */
+class DocAccessibleChild : public PDocAccessibleChild
+{
+public:
+ DocAccessibleChild(DocAccessible* aDoc) :
+ mDoc(aDoc)
+ { MOZ_COUNT_CTOR(DocAccessibleChild); }
+ ~DocAccessibleChild()
+ {
+ mDoc->SetIPCDoc(nullptr);
+ MOZ_COUNT_DTOR(DocAccessibleChild);
+ }
+
+ void ShowEvent(AccShowEvent* aShowEvent);
+
+private:
+ DocAccessible* mDoc;
+};
+
+}
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/DocAccessibleParent.cpp
@@ -0,0 +1,114 @@
+/* -*- 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/. */
+
+#include "DocAccessibleParent.h"
+#include "nsAutoPtr.h"
+#include "mozilla/a11y/Platform.h"
+
+namespace mozilla {
+namespace a11y {
+
+bool
+DocAccessibleParent::RecvShowEvent(const ShowEventData& aData)
+{
+ if (aData.NewTree().IsEmpty()) {
+ NS_ERROR("no children being added");
+ return false;
+ }
+
+ ProxyAccessible* parent = nullptr;
+ if (aData.ID()) {
+ ProxyEntry* e = mAccessibles.GetEntry(aData.ID());
+ if (e)
+ parent = e->mProxy;
+ } else {
+ parent = this;
+ }
+
+ // XXX This should really never happen, but sometimes we fail to fire the
+ // required show events.
+ if (!parent) {
+ NS_ERROR("adding child to unknown accessible");
+ return false;
+ }
+
+ uint32_t newChildIdx = aData.Idx();
+ if (newChildIdx > parent->ChildrenCount()) {
+ NS_ERROR("invalid index to add child at");
+ return false;
+ }
+
+ uint32_t consumed = AddSubtree(parent, aData.NewTree(), 0, newChildIdx);
+ MOZ_ASSERT(consumed == aData.NewTree().Length());
+ for (uint32_t i = 0; i < consumed; i++) {
+ uint64_t id = aData.NewTree()[i].ID();
+ MOZ_ASSERT(mAccessibles.GetEntry(id));
+ }
+
+ return consumed;
+}
+
+uint32_t
+DocAccessibleParent::AddSubtree(ProxyAccessible* aParent,
+ const nsTArray<a11y::AccessibleData>& aNewTree,
+ uint32_t aIdx, uint32_t aIdxInParent)
+{
+ if (aNewTree.Length() <= aIdx) {
+ NS_ERROR("bad index in serialized tree!");
+ return 0;
+ }
+
+ const AccessibleData& newChild = aNewTree[aIdx];
+ if (newChild.Role() > roles::LAST_ROLE) {
+ NS_ERROR("invalid role");
+ return 0;
+ }
+
+ auto role = static_cast<a11y::role>(newChild.Role());
+ ProxyAccessible* newProxy =
+ new ProxyAccessible(newChild.ID(), aParent, this, role, newChild.Name());
+ aParent->AddChildAt(aIdxInParent, newProxy);
+ mAccessibles.PutEntry(newChild.ID())->mProxy = newProxy;
+ ProxyCreated(newProxy);
+
+ uint32_t accessibles = 1;
+ uint32_t kids = newChild.ChildrenCount();
+ for (uint32_t i = 0; i < kids; i++) {
+ uint32_t consumed = AddSubtree(newProxy, aNewTree, aIdx + accessibles, i);
+ if (!consumed)
+ return 0;
+
+ accessibles += consumed;
+ }
+
+ MOZ_ASSERT(newProxy->ChildrenCount() == kids);
+
+ return accessibles;
+}
+
+bool
+DocAccessibleParent::RecvHideEvent(const uint64_t& aRootID)
+{
+ ProxyEntry* rootEntry = mAccessibles.GetEntry(aRootID);
+ if (!rootEntry) {
+ NS_ERROR("invalid root being removed!");
+ return true;
+ }
+
+ ProxyAccessible* root = rootEntry->mProxy;
+ if (!root) {
+ NS_ERROR("invalid root being removed!");
+ return true;
+ }
+
+ ProxyAccessible* parent = root->Parent();
+ parent->RemoveChild(root);
+ root->Shutdown();
+
+ return true;
+}
+}
+}
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/DocAccessibleParent.h
@@ -0,0 +1,141 @@
+/* -*- 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() :
+ mParentDoc(nullptr)
+ { MOZ_COUNT_CTOR_INHERITED(DocAccessibleParent, ProxyAccessible); }
+ ~DocAccessibleParent()
+ {
+ MOZ_COUNT_DTOR_INHERITED(DocAccessibleParent, ProxyAccessible);
+ MOZ_ASSERT(mChildDocs.Length() == 0);
+ MOZ_ASSERT(!mParentDoc);
+ }
+
+ /*
+ * Called when a message from a document in a child process notifies the main
+ * process it is firing an event.
+ */
+ virtual bool RecvEvent(const uint32_t& aType) MOZ_OVERRIDE
+ {
+ return true;
+ }
+
+ virtual bool RecvShowEvent(const ShowEventData& aData) MOZ_OVERRIDE;
+ virtual bool RecvHideEvent(const uint64_t& aRootID) MOZ_OVERRIDE;
+
+ virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE
+ {
+ MOZ_ASSERT(mChildDocs.IsEmpty(),
+ "why wheren't the child docs destroyed already?");
+ mParentDoc ? mParentDoc->RemoveChildDoc(this)
+ : GetAccService()->RemoteDocShutdown(this);
+ }
+
+ /*
+ * Return the main processes representation of the parent document (if any)
+ * of the document this object represents.
+ */
+ DocAccessibleParent* Parent() 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)
+ {
+ ProxyAccessible* outerDoc = mAccessibles.GetEntry(aParentID)->mProxy;
+ if (!outerDoc)
+ return false;
+
+ aChildDoc->mParent = outerDoc;
+ outerDoc->SetChildDoc(aChildDoc);
+ mChildDocs.AppendElement(aChildDoc);
+ aChildDoc->mParentDoc = this;
+ return 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->mParent->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());
+ }
+
+private:
+
+ class ProxyEntry : public PLDHashEntryHdr
+ {
+ public:
+ 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);
+
+ 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;
+};
+
+}
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/PDocAccessible.ipdl
@@ -0,0 +1,44 @@
+/* -*- 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/. */
+
+include protocol PContent;
+
+namespace mozilla {
+namespace a11y {
+
+struct AccessibleData
+{
+ uint64_t ID;
+ uint32_t Role;
+ uint32_t ChildrenCount;
+ nsString Name;
+};
+
+struct ShowEventData
+{
+ uint64_t ID;
+ uint32_t Idx;
+ AccessibleData[] NewTree;
+};
+
+protocol PDocAccessible
+{
+ manager PContent;
+
+parent:
+ __delete__();
+
+ /*
+ * Notify the parent process the document in the child process is firing an
+ * event.
+ */
+ Event(uint32_t type);
+ ShowEvent(ShowEventData data);
+ HideEvent(uint64_t aRootID);
+};
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/ProxyAccessible.cpp
@@ -0,0 +1,42 @@
+/* -*- 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/. */
+
+#include "ProxyAccessible.h"
+#include "DocAccessibleParent.h"
+#include "mozilla/a11y/Platform.h"
+
+namespace mozilla {
+namespace a11y {
+
+void
+ProxyAccessible::Shutdown()
+{
+ MOZ_ASSERT(!mOuterDoc);
+
+ uint32_t childCount = mChildren.Length();
+ for (uint32_t idx = 0; idx < childCount; idx++)
+ mChildren[idx]->Shutdown();
+
+ mChildren.Clear();
+ ProxyDestroyed(this);
+ mDoc->RemoveAccessible(this);
+}
+
+void
+ProxyAccessible::SetChildDoc(DocAccessibleParent* aParent)
+{
+ if (aParent) {
+ MOZ_ASSERT(mChildren.IsEmpty());
+ mChildren.AppendElement(aParent);
+ mOuterDoc = true;
+ } else {
+ MOZ_ASSERT(mChildren.Length() == 1);
+ mChildren.Clear();
+ mOuterDoc = false;
+ }
+}
+}
+}
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/ProxyAccessible.h
@@ -0,0 +1,88 @@
+/* -*- 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_ProxyAccessible_h
+#define mozilla_a11y_ProxyAccessible_h
+
+#include "mozilla/a11y/Role.h"
+#include "nsString.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace a11y {
+
+class DocAccessibleParent;
+
+class ProxyAccessible
+{
+public:
+
+ ProxyAccessible(uint64_t aID, ProxyAccessible* aParent,
+ DocAccessibleParent* aDoc, role aRole,
+ const nsString& aName) :
+ mParent(aParent), mDoc(aDoc), mID(aID), mRole(aRole), mOuterDoc(false), mName(aName)
+ {
+ MOZ_COUNT_CTOR(ProxyAccessible);
+ }
+ ~ProxyAccessible() { MOZ_COUNT_DTOR(ProxyAccessible); }
+
+ void AddChildAt(uint32_t aIdx, ProxyAccessible* aChild)
+ { mChildren.InsertElementAt(aIdx, aChild); }
+
+ uint32_t ChildrenCount() const { return mChildren.Length(); }
+
+ void Shutdown();
+
+ void SetChildDoc(DocAccessibleParent*);
+
+ /**
+ * Remove The given child.
+ */
+ void RemoveChild(ProxyAccessible* aChild)
+ { mChildren.RemoveElement(aChild); }
+
+ /**
+ * Return the proxy for the parent of the wrapped accessible.
+ */
+ ProxyAccessible* Parent() const { return mParent; }
+
+ /**
+ * Get the role of the accessible we're proxying.
+ */
+ role Role() const { return mRole; }
+
+ /**
+ * Allow the platform to store a pointers worth of data on us.
+ */
+ uintptr_t GetWrapper() const { return mWrapper; }
+ void SetWrapper(uintptr_t aWrapper) { mWrapper = aWrapper; }
+
+ /*
+ * Return the ID of the accessible being proxied.
+ */
+ uint64_t ID() const { return mID; }
+
+protected:
+ ProxyAccessible() :
+ mParent(nullptr), mDoc(nullptr) { MOZ_COUNT_CTOR(ProxyAccessible); }
+
+protected:
+ ProxyAccessible* mParent;
+
+private:
+ nsTArray<ProxyAccessible*> mChildren;
+ DocAccessibleParent* mDoc;
+ uintptr_t mWrapper;
+ uint64_t mID;
+ role mRole : 31;
+ bool mOuterDoc : 1;
+ nsString mName;
+};
+
+}
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/moz.build
@@ -0,0 +1,31 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+IPDL_SOURCES += ['PDocAccessible.ipdl']
+
+# with --disable-accessibility we need to compile PDocAccessible.ipdl, but not
+# the C++.
+if CONFIG['ACCESSIBILITY']:
+ EXPORTS.mozilla.a11y += [
+ 'DocAccessibleChild.h',
+ 'DocAccessibleParent.h',
+ 'ProxyAccessible.h'
+ ]
+
+ SOURCES += [
+ 'DocAccessibleChild.cpp',
+ 'DocAccessibleParent.cpp',
+ 'ProxyAccessible.cpp'
+ ]
+
+ LOCAL_INCLUDES += [
+ '../base',
+ '../generic',
+ ]
+
+ FINAL_LIBRARY = 'xul'
+
+include('/ipc/chromium/chromium-config.mozbuild')
--- a/accessible/mac/Platform.mm
+++ b/accessible/mac/Platform.mm
@@ -28,16 +28,25 @@ PlatformInit()
{
}
void
PlatformShutdown()
{
}
+void
+ProxyCreated(ProxyAccessible*)
+{
+}
+
+void
+ProxyDestroyed(ProxyAccessible*)
+{
+}
}
}
@interface GeckoNSApplication(a11y)
-(void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute;
@end
@implementation GeckoNSApplication(a11y)
--- a/accessible/moz.build
+++ b/accessible/moz.build
@@ -10,14 +10,14 @@ if CONFIG['MOZ_ENABLE_GTK']:
DIRS += ['atk']
elif toolkit == 'windows':
DIRS += ['windows']
elif toolkit == 'cocoa':
DIRS += ['mac']
else:
DIRS += ['other']
-DIRS += ['base', 'generic', 'html', 'interfaces', 'jsat', 'xpcom']
+DIRS += ['base', 'generic', 'html', 'interfaces', 'ipc', 'jsat', 'xpcom']
if CONFIG['MOZ_XUL']:
DIRS += ['xul']
TEST_DIRS += ['tests/mochitest']
--- a/accessible/other/Platform.cpp
+++ b/accessible/other/Platform.cpp
@@ -13,8 +13,18 @@ void
a11y::PlatformInit()
{
}
void
a11y::PlatformShutdown()
{
}
+
+void
+a11y::ProxyCreated(ProxyAccessible*)
+{
+}
+
+void
+a11y::ProxyDestroyed(ProxyAccessible*)
+{
+}
--- a/accessible/windows/msaa/Platform.cpp
+++ b/accessible/windows/msaa/Platform.cpp
@@ -29,8 +29,17 @@ a11y::PlatformInit()
void
a11y::PlatformShutdown()
{
::DestroyCaret();
nsWinUtils::ShutdownWindowEmulation();
}
+void
+a11y::ProxyCreated(ProxyAccessible*)
+{
+}
+
+void
+a11y::ProxyDestroyed(ProxyAccessible*)
+{
+}
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -14,16 +14,19 @@
#include "ContentChild.h"
#include "BlobChild.h"
#include "CrashReporterChild.h"
#include "TabChild.h"
#include "mozilla/Attributes.h"
+#ifdef ACCESSIBILITY
+#include "mozilla/a11y/DocAccessibleChild.h"
+#endif
#include "mozilla/Preferences.h"
#include "mozilla/dom/ContentBridgeChild.h"
#include "mozilla/dom/ContentBridgeParent.h"
#include "mozilla/dom/DOMStorageIPC.h"
#include "mozilla/dom/ExternalHelperAppChild.h"
#include "mozilla/dom/PCrashReporterChild.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/asmjscache/AsmJSCache.h"
@@ -726,16 +729,32 @@ ContentChild::InitXPCOM()
// This object is held alive by the observer service.
nsRefPtr<SystemMessageHandledObserver> sysMsgObserver =
new SystemMessageHandledObserver();
sysMsgObserver->Init();
InitOnContentProcessCreated();
}
+a11y::PDocAccessibleChild*
+ContentChild::AllocPDocAccessibleChild(PDocAccessibleChild*, const uint64_t&)
+{
+ MOZ_ASSERT(false, "should never call this!");
+ return nullptr;
+}
+
+bool
+ContentChild::DeallocPDocAccessibleChild(a11y::PDocAccessibleChild* aChild)
+{
+#ifdef ACCESSIBILITY
+ delete static_cast<mozilla::a11y::DocAccessibleChild*>(aChild);
+#endif
+ return true;
+}
+
PMemoryReportRequestChild*
ContentChild::AllocPMemoryReportRequestChild(const uint32_t& aGeneration,
const bool &aAnonymize,
const bool &aMinimizeMemoryUsage,
const MaybeFileDesc& aDMDFile)
{
MemoryReportRequestChild *actor =
new MemoryReportRequestChild(aGeneration, aAnonymize, aDMDFile);
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -377,16 +377,18 @@ public:
const bool& aIsForBrowser) MOZ_OVERRIDE;
virtual bool RecvPBrowserConstructor(PBrowserChild* aCctor,
const IPCTabContext& aContext,
const uint32_t& aChromeFlags,
const uint64_t& aID,
const bool& aIsForApp,
const bool& aIsForBrowser) MOZ_OVERRIDE;
+ virtual PDocAccessibleChild* AllocPDocAccessibleChild(PDocAccessibleChild*, const uint64_t&) MOZ_OVERRIDE;
+ virtual bool DeallocPDocAccessibleChild(PDocAccessibleChild*) MOZ_OVERRIDE;
void GetAvailableDictionaries(InfallibleTArray<nsString>& aDictionaries);
private:
virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
virtual void ProcessingError(Result what) MOZ_OVERRIDE;
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -25,16 +25,20 @@
#include <set>
#include "AppProcessChecker.h"
#include "AudioChannelService.h"
#include "BlobParent.h"
#include "CrashReporterParent.h"
#include "IHistory.h"
#include "mozIApplication.h"
+#ifdef ACCESSIBILITY
+#include "mozilla/a11y/DocAccessibleParent.h"
+#include "nsAccessibilityService.h"
+#endif
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/dom/DataStoreService.h"
#include "mozilla/dom/DOMStorageIPC.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/ExternalHelperAppParent.h"
#include "mozilla/dom/FileSystemRequestParent.h"
#include "mozilla/dom/GeolocationBinding.h"
@@ -2701,16 +2705,52 @@ ContentParent::Observe(nsISupports* aSub
}
#endif
else if (!strcmp(aTopic, "app-theme-changed")) {
unused << SendOnAppThemeChanged();
}
return NS_OK;
}
+ a11y::PDocAccessibleParent*
+ContentParent::AllocPDocAccessibleParent(PDocAccessibleParent* aParent, const uint64_t&)
+{
+#ifdef ACCESSIBILITY
+ return new a11y::DocAccessibleParent();
+#else
+ return nullptr;
+#endif
+}
+
+bool
+ContentParent::DeallocPDocAccessibleParent(PDocAccessibleParent* aParent)
+{
+#ifdef ACCESSIBILITY
+ delete static_cast<a11y::DocAccessibleParent*>(aParent);
+#endif
+ return true;
+}
+
+bool
+ContentParent::RecvPDocAccessibleConstructor(PDocAccessibleParent* aDoc, PDocAccessibleParent* aParentDoc, const uint64_t& aParentID)
+{
+#ifdef ACCESSIBILITY
+ auto doc = static_cast<a11y::DocAccessibleParent*>(aDoc);
+ if (aParentDoc) {
+ MOZ_ASSERT(aParentID);
+ auto parentDoc = static_cast<a11y::DocAccessibleParent*>(aParentDoc);
+ return parentDoc->AddChildDoc(doc, aParentID);
+ } else {
+ MOZ_ASSERT(!aParentID);
+ GetAccService()->RemoteDocAdded(doc);
+ }
+#endif
+ return true;
+}
+
PCompositorParent*
ContentParent::AllocPCompositorParent(mozilla::ipc::Transport* aTransport,
base::ProcessId aOtherProcess)
{
return CompositorParent::Create(aTransport, aOtherProcess);
}
PImageBridgeParent*
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -674,16 +674,21 @@ private:
const nsCString& aOrigin,
const nsString& aDatabaseName,
const int64_t& aFileId,
int32_t* aRefCnt,
int32_t* aDBRefCnt,
int32_t* aSliceRefCnt,
bool* aResult) MOZ_OVERRIDE;
+ virtual PDocAccessibleParent* AllocPDocAccessibleParent(PDocAccessibleParent*, const uint64_t&) MOZ_OVERRIDE;
+ virtual bool DeallocPDocAccessibleParent(PDocAccessibleParent*) MOZ_OVERRIDE;
+ virtual bool RecvPDocAccessibleConstructor(PDocAccessibleParent* aDoc,
+ PDocAccessibleParent* aParentDoc, const uint64_t& aParentID) MOZ_OVERRIDE;
+
// If you add strong pointers to cycle collected objects here, be sure to
// release these objects in ShutDownProcess. See the comment there for more
// details.
GeckoChildProcessHost* mSubprocess;
ContentParent* mOpener;
uint64_t mChildID;
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -9,16 +9,17 @@ include protocol PBackground;
include protocol PBlob;
include protocol PBluetooth;
include protocol PBrowser;
include protocol PCellBroadcast;
include protocol PCompositor;
include protocol PContentBridge;
include protocol PCycleCollectWithLogs;
include protocol PCrashReporter;
+include protocol PDocAccessible;
include protocol PExternalHelperApp;
include protocol PDeviceStorageRequest;
include protocol PFileDescriptorSet;
include protocol PFMRadio;
include protocol PFileSystemRequest;
include protocol PHal;
include protocol PImageBridge;
include protocol PMemoryReportRequest;
@@ -328,16 +329,17 @@ prio(normal upto high) intr protocol PCo
manages PAsmJSCacheEntry;
manages PBlob;
manages PBluetooth;
manages PBrowser;
manages PCellBroadcast;
manages PCrashReporter;
manages PCycleCollectWithLogs;
+ manages PDocAccessible;
manages PDeviceStorageRequest;
manages PFileSystemRequest;
manages PExternalHelperApp;
manages PFileDescriptorSet;
manages PFMRadio;
manages PHal;
manages PMemoryReportRequest;
manages PMobileConnection;
@@ -487,16 +489,24 @@ child:
/**
* Notify windows in the child to apply a new app style.
*/
OnAppThemeChanged();
parent:
/**
+ * Tell the parent process a new accessible document has been created.
+ * aParentDoc is the accessible document it was created in if any, and
+ * aParentAcc is the id of the accessible in that document the new document
+ * is a child of.
+ */
+ PDocAccessible(nullable PDocAccessible aParentDoc, uint64_t aParentAcc);
+
+ /**
* Tell the content process some attributes of itself. This is
* among the first information queried by content processes after
* startup. (The message is sync to allow the content process to
* control when it receives the information.)
*
* |id| is a unique ID among all subprocesses. When |isForApp &&
* isForBrowser|, we're loading <browser> for an app. When
* |isForBrowser|, we're loading <browser>. When |!isForApp &&
--- a/toolkit/toolkit.mozbuild
+++ b/toolkit/toolkit.mozbuild
@@ -116,16 +116,18 @@ DIRS += [
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
DIRS += ['/other-licenses/skia-npapi']
if CONFIG['MOZ_UNIVERSALCHARDET']:
DIRS += ['/extensions/universalchardet']
if CONFIG['ACCESSIBILITY']:
DIRS += ['/accessible']
+else:
+ DIRS += ['/accessible/ipc']
# toolkit
DIRS += ['/profile']
# This must precede xpfe.
if CONFIG['MOZ_JPROF']:
DIRS += ['/tools/jprof']