fune/accessible/ipc/win/DocAccessibleChild.cpp
2020-07-04 09:38:43 +00:00

320 lines
10 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/. */
#include "DocAccessibleChild.h"
#include "nsAccessibilityService.h"
#include "Accessible-inl.h"
#include "mozilla/a11y/PlatformChild.h"
#include "mozilla/ClearOnShutdown.h"
#include "RootAccessible.h"
namespace mozilla {
namespace a11y {
static StaticAutoPtr<PlatformChild> sPlatformChild;
DocAccessibleChild::DocAccessibleChild(DocAccessible* aDoc, IProtocol* aManager)
: DocAccessibleChildBase(aDoc), mEmulatedWindowHandle(nullptr) {
MOZ_COUNT_CTOR_INHERITED(DocAccessibleChild, DocAccessibleChildBase);
if (!sPlatformChild) {
sPlatformChild = new PlatformChild();
ClearOnShutdown(&sPlatformChild, ShutdownPhase::Shutdown);
}
SetManager(aManager);
}
DocAccessibleChild::~DocAccessibleChild() {
MOZ_COUNT_DTOR_INHERITED(DocAccessibleChild, DocAccessibleChildBase);
}
void DocAccessibleChild::Shutdown() {
if (IsConstructedInParentProcess()) {
DocAccessibleChildBase::Shutdown();
return;
}
PushDeferredEvent(MakeUnique<SerializedShutdown>(this));
DetachDocument();
}
ipc::IPCResult DocAccessibleChild::RecvParentCOMProxy(
const IDispatchHolder& aParentCOMProxy) {
MOZ_ASSERT(!aParentCOMProxy.IsNull());
mParentProxy.reset(const_cast<IDispatchHolder&>(aParentCOMProxy).Release());
SetConstructedInParentProcess();
for (uint32_t i = 0, l = mDeferredEvents.Length(); i < l; ++i) {
mDeferredEvents[i]->Dispatch();
}
mDeferredEvents.Clear();
return IPC_OK();
}
ipc::IPCResult DocAccessibleChild::RecvEmulatedWindow(
const WindowsHandle& aEmulatedWindowHandle,
const IDispatchHolder& aEmulatedWindowCOMProxy) {
mEmulatedWindowHandle = reinterpret_cast<HWND>(aEmulatedWindowHandle);
if (!aEmulatedWindowCOMProxy.IsNull()) {
MOZ_ASSERT(!mEmulatedWindowProxy);
mEmulatedWindowProxy.reset(
const_cast<IDispatchHolder&>(aEmulatedWindowCOMProxy).Release());
}
return IPC_OK();
}
ipc::IPCResult DocAccessibleChild::RecvTopLevelDocCOMProxy(
const IAccessibleHolder& aCOMProxy) {
MOZ_ASSERT(!aCOMProxy.IsNull());
mTopLevelDocProxy.reset(const_cast<IAccessibleHolder&>(aCOMProxy).Release());
return IPC_OK();
}
HWND DocAccessibleChild::GetNativeWindowHandle() const {
if (mEmulatedWindowHandle) {
return mEmulatedWindowHandle;
}
auto browser = static_cast<dom::BrowserChild*>(Manager());
MOZ_ASSERT(browser);
// Iframe documents use the same window handle as their top level document.
auto topDoc = static_cast<DocAccessibleChild*>(
browser->GetTopLevelDocAccessibleChild());
MOZ_ASSERT(topDoc);
if (topDoc != this && topDoc->mEmulatedWindowHandle) {
return topDoc->mEmulatedWindowHandle;
}
return reinterpret_cast<HWND>(browser->GetNativeWindowHandle());
}
void DocAccessibleChild::PushDeferredEvent(UniquePtr<DeferredEvent> aEvent) {
DocAccessibleChild* topLevelIPCDoc = nullptr;
if (mDoc && mDoc->IsRoot()) {
topLevelIPCDoc = this;
} else {
auto browserChild = static_cast<dom::BrowserChild*>(Manager());
if (!browserChild) {
return;
}
topLevelIPCDoc = static_cast<DocAccessibleChild*>(
browserChild->GetTopLevelDocAccessibleChild());
}
if (topLevelIPCDoc) {
topLevelIPCDoc->mDeferredEvents.AppendElement(std::move(aEvent));
}
}
bool DocAccessibleChild::SendEvent(const uint64_t& aID, const uint32_t& aType) {
if (IsConstructedInParentProcess()) {
return PDocAccessibleChild::SendEvent(aID, aType);
}
PushDeferredEvent(MakeUnique<SerializedEvent>(this, aID, aType));
return false;
}
void DocAccessibleChild::MaybeSendShowEvent(ShowEventData& aData,
bool aFromUser) {
if (IsConstructedInParentProcess()) {
Unused << SendShowEvent(aData, aFromUser);
return;
}
PushDeferredEvent(MakeUnique<SerializedShow>(this, aData, aFromUser));
}
bool DocAccessibleChild::SendHideEvent(const uint64_t& aRootID,
const bool& aFromUser) {
if (IsConstructedInParentProcess()) {
return PDocAccessibleChild::SendHideEvent(aRootID, aFromUser);
}
PushDeferredEvent(MakeUnique<SerializedHide>(this, aRootID, aFromUser));
return true;
}
bool DocAccessibleChild::SendStateChangeEvent(const uint64_t& aID,
const uint64_t& aState,
const bool& aEnabled) {
if (IsConstructedInParentProcess()) {
return PDocAccessibleChild::SendStateChangeEvent(aID, aState, aEnabled);
}
PushDeferredEvent(
MakeUnique<SerializedStateChange>(this, aID, aState, aEnabled));
return true;
}
LayoutDeviceIntRect DocAccessibleChild::GetCaretRectFor(const uint64_t& aID) {
Accessible* target;
if (aID) {
target = reinterpret_cast<Accessible*>(aID);
} else {
target = mDoc;
}
MOZ_ASSERT(target);
HyperTextAccessible* text = target->AsHyperText();
if (!text) {
return LayoutDeviceIntRect();
}
nsIWidget* widget = nullptr;
return text->GetCaretRect(&widget);
}
bool DocAccessibleChild::SendFocusEvent(const uint64_t& aID) {
return SendFocusEvent(aID, GetCaretRectFor(aID));
}
bool DocAccessibleChild::SendFocusEvent(const uint64_t& aID,
const LayoutDeviceIntRect& aCaretRect) {
if (IsConstructedInParentProcess()) {
return PDocAccessibleChild::SendFocusEvent(aID, aCaretRect);
}
PushDeferredEvent(MakeUnique<SerializedFocus>(this, aID, aCaretRect));
return true;
}
bool DocAccessibleChild::SendCaretMoveEvent(const uint64_t& aID,
const int32_t& aOffset,
const bool& aIsSelectionCollapsed) {
return SendCaretMoveEvent(aID, GetCaretRectFor(aID), aOffset,
aIsSelectionCollapsed);
}
bool DocAccessibleChild::SendCaretMoveEvent(
const uint64_t& aID, const LayoutDeviceIntRect& aCaretRect,
const int32_t& aOffset, const bool& aIsSelectionCollapsed) {
if (IsConstructedInParentProcess()) {
return PDocAccessibleChild::SendCaretMoveEvent(aID, aCaretRect, aOffset,
aIsSelectionCollapsed);
}
PushDeferredEvent(MakeUnique<SerializedCaretMove>(
this, aID, aCaretRect, aOffset, aIsSelectionCollapsed));
return true;
}
bool DocAccessibleChild::SendTextChangeEvent(
const uint64_t& aID, const nsString& aStr, const int32_t& aStart,
const uint32_t& aLen, const bool& aIsInsert, const bool& aFromUser,
const bool aDoSync) {
if (IsConstructedInParentProcess()) {
if (aDoSync) {
// The AT is going to need to reenter content while the event is being
// dispatched synchronously.
return PDocAccessibleChild::SendSyncTextChangeEvent(
aID, aStr, aStart, aLen, aIsInsert, aFromUser);
}
return PDocAccessibleChild::SendTextChangeEvent(aID, aStr, aStart, aLen,
aIsInsert, aFromUser);
}
PushDeferredEvent(MakeUnique<SerializedTextChange>(
this, aID, aStr, aStart, aLen, aIsInsert, aFromUser));
return true;
}
bool DocAccessibleChild::SendSelectionEvent(const uint64_t& aID,
const uint64_t& aWidgetID,
const uint32_t& aType) {
if (IsConstructedInParentProcess()) {
return PDocAccessibleChild::SendSelectionEvent(aID, aWidgetID, aType);
}
PushDeferredEvent(
MakeUnique<SerializedSelection>(this, aID, aWidgetID, aType));
return true;
}
bool DocAccessibleChild::SendRoleChangedEvent(const a11y::role& aRole) {
if (IsConstructedInParentProcess()) {
return PDocAccessibleChild::SendRoleChangedEvent(aRole);
}
PushDeferredEvent(MakeUnique<SerializedRoleChanged>(this, aRole));
return true;
}
bool DocAccessibleChild::SendScrollingEvent(const uint64_t& aID,
const uint64_t& aType,
const uint32_t& aScrollX,
const uint32_t& aScrollY,
const uint32_t& aMaxScrollX,
const uint32_t& aMaxScrollY) {
if (IsConstructedInParentProcess()) {
return PDocAccessibleChild::SendScrollingEvent(
aID, aType, aScrollX, aScrollY, aMaxScrollX, aMaxScrollY);
}
PushDeferredEvent(MakeUnique<SerializedScrolling>(
this, aID, aType, aScrollX, aScrollY, aMaxScrollX, aMaxScrollY));
return true;
}
bool DocAccessibleChild::ConstructChildDocInParentProcess(
DocAccessibleChild* aNewChildDoc, uint64_t aUniqueID, uint32_t aMsaaID) {
if (IsConstructedInParentProcess()) {
// We may send the constructor immediately
auto browserChild = static_cast<dom::BrowserChild*>(Manager());
MOZ_ASSERT(browserChild);
bool result = browserChild->SendPDocAccessibleConstructor(
aNewChildDoc, this, aUniqueID, aMsaaID, IAccessibleHolder());
if (result) {
aNewChildDoc->SetConstructedInParentProcess();
}
return result;
}
PushDeferredEvent(MakeUnique<SerializedChildDocConstructor>(
aNewChildDoc, this, aUniqueID, aMsaaID));
return true;
}
bool DocAccessibleChild::SendBindChildDoc(DocAccessibleChild* aChildDoc,
const uint64_t& aNewParentID) {
if (IsConstructedInParentProcess()) {
return DocAccessibleChildBase::SendBindChildDoc(aChildDoc, aNewParentID);
}
PushDeferredEvent(
MakeUnique<SerializedBindChildDoc>(this, aChildDoc, aNewParentID));
return true;
}
ipc::IPCResult DocAccessibleChild::RecvRestoreFocus() {
FocusMgr()->ForceFocusEvent();
return IPC_OK();
}
void DocAccessibleChild::SetEmbedderOnBridge(dom::BrowserBridgeChild* aBridge,
uint64_t aID) {
if (CanSend()) {
aBridge->SendSetEmbedderAccessible(this, aID);
} else {
// This DocAccessibleChild hasn't sent the constructor to the parent
// process yet. This happens if the top level document hasn't received its
// parent COM proxy yet, in which case sending constructors for child
// documents gets deferred. We must also defer sending this as an embedder.
MOZ_ASSERT(!IsConstructedInParentProcess());
PushDeferredEvent(MakeUnique<SerializedSetEmbedder>(aBridge, this, aID));
}
}
} // namespace a11y
} // namespace mozilla