Bug 1206711 - add support for HWND emulation for content top level docs on Windows. r=tbsaunde

MozReview-Commit-ID: GQ1LxCwtv3j
This commit is contained in:
Yura Zenevich 2016-09-29 16:00:50 -04:00
parent 5650342313
commit 26f2c60483
11 changed files with 110 additions and 10 deletions

View file

@ -12,6 +12,13 @@
#include "nsAccUtils.h"
#include "nsCoreUtils.h"
#if defined(XP_WIN)
#include "AccessibleWrap.h"
#include "Compatibility.h"
#include "nsWinUtils.h"
#include "RootAccessible.h"
#endif
namespace mozilla {
namespace a11y {
@ -525,7 +532,43 @@ DocAccessibleParent::SetCOMProxy(const RefPtr<IAccessible>& aCOMProxy)
IAccessibleHolder::COMPtrType ptr(rawNative);
IAccessibleHolder holder(Move(ptr));
Unused << SendParentCOMProxy(holder);
if (nsWinUtils::IsWindowEmulationStarted()) {
RootAccessible* rootDocument = outerDoc->RootAccessible();
MOZ_ASSERT(rootDocument);
bool isActive = true;
nsIntRect rect(CW_USEDEFAULT, CW_USEDEFAULT, 0, 0);
if (Compatibility::IsDolphin()) {
rect = Bounds();
nsIntRect rootRect = rootDocument->Bounds();
rect.x = rootRect.x - rect.x;
rect.y -= rootRect.y;
tab->GetDocShellIsActive(&isActive);
}
HWND parentWnd = reinterpret_cast<HWND>(rootDocument->GetNativeWindow());
HWND hWnd = nsWinUtils::CreateNativeWindow(kClassNameTabContent,
parentWnd, rect.x, rect.y,
rect.width, rect.height,
isActive);
if (hWnd) {
// Attach accessible document to the emulated native window
::SetPropW(hWnd, kPropNameDocAccParent, (HANDLE)this);
SetEmulatedWindowHandle(hWnd);
}
}
Unused << SendParentCOMProxy(holder, reinterpret_cast<uintptr_t>(
mEmulatedWindowHandle));
}
void
DocAccessibleParent::SetEmulatedWindowHandle(HWND aWindowHandle)
{
if (!aWindowHandle && mEmulatedWindowHandle && IsTopLevel()) {
::DestroyWindow(mEmulatedWindowHandle);
}
mEmulatedWindowHandle = aWindowHandle;
}
mozilla::ipc::IPCResult

View file

@ -30,6 +30,9 @@ public:
DocAccessibleParent() :
ProxyAccessible(this), mParentDoc(nullptr),
mTopLevel(false), mShutdown(false)
#if defined(XP_WIN)
, mEmulatedWindowHandle(nullptr)
#endif // defined(XP_WIN)
{ MOZ_COUNT_CTOR_INHERITED(DocAccessibleParent, ProxyAccessible); }
~DocAccessibleParent()
{
@ -151,6 +154,13 @@ public:
virtual mozilla::ipc::IPCResult RecvGetWindowedPluginIAccessible(
const WindowsHandle& aHwnd, IAccessibleHolder* aPluginCOMProxy) override;
/**
* Set emulated native window handle for a document.
* @param aWindowHandle emulated native window handle
*/
void SetEmulatedWindowHandle(HWND aWindowHandle);
HWND GetEmulatedWindowHandle() const { return mEmulatedWindowHandle; }
#endif
private:
@ -187,6 +197,11 @@ private:
nsTArray<DocAccessibleParent*> mChildDocs;
DocAccessibleParent* mParentDoc;
#if defined(XP_WIN)
// The handle associated with the emulated window that contains this document
HWND mEmulatedWindowHandle;
#endif
/*
* 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.

View file

@ -18,6 +18,7 @@ static StaticAutoPtr<PlatformChild> sPlatformChild;
DocAccessibleChild::DocAccessibleChild(DocAccessible* aDoc)
: DocAccessibleChildBase(aDoc)
, mEmulatedWindowHandle(nullptr)
, mIsRemoteConstructed(false)
{
MOZ_COUNT_CTOR_INHERITED(DocAccessibleChild, DocAccessibleChildBase);
@ -45,11 +46,13 @@ DocAccessibleChild::Shutdown()
}
ipc::IPCResult
DocAccessibleChild::RecvParentCOMProxy(const IAccessibleHolder& aParentCOMProxy)
DocAccessibleChild::RecvParentCOMProxy(const IAccessibleHolder& aParentCOMProxy,
const WindowsHandle& aEmulatedWindowHandle)
{
MOZ_ASSERT(!mParentProxy && !aParentCOMProxy.IsNull());
mParentProxy.reset(const_cast<IAccessibleHolder&>(aParentCOMProxy).Release());
SetConstructedInParentProcess();
mEmulatedWindowHandle = reinterpret_cast<HWND>(aEmulatedWindowHandle);
for (uint32_t i = 0, l = mDeferredEvents.Length(); i < l; ++i) {
mDeferredEvents[i]->Dispatch();

View file

@ -28,7 +28,10 @@ public:
virtual void Shutdown() override;
virtual ipc::IPCResult
RecvParentCOMProxy(const IAccessibleHolder& aParentCOMProxy) override;
RecvParentCOMProxy(const IAccessibleHolder& aParentCOMProxy,
const WindowsHandle& aEmulatedWindowHandle) override;
HWND GetEmulatedWindowHandle() const { return mEmulatedWindowHandle; }
IAccessible* GetParentIAccessible() const { return mParentProxy.get(); }
@ -310,6 +313,7 @@ private:
bool mIsRemoteConstructed;
mscom::ProxyUniquePtr<IAccessible> mParentProxy;
nsTArray<UniquePtr<DeferredEvent>> mDeferredEvents;
HWND mEmulatedWindowHandle;
};
} // namespace a11y

View file

@ -66,7 +66,8 @@ parent:
returns (IAccessibleHolder aPluginCOMProxy);
child:
async ParentCOMProxy(IAccessibleHolder aParentCOMProxy);
async ParentCOMProxy(IAccessibleHolder aParentCOMProxy,
WindowsHandle aEmulatedWindowHandle);
async __delete__();
};

View file

@ -120,6 +120,11 @@ DocAccessibleWrap::GetNativeWindow() const
{
if (XRE_IsContentProcess()) {
DocAccessibleChild* ipcDoc = IPCDoc();
HWND hWnd = ipcDoc->GetEmulatedWindowHandle();
if (hWnd) {
return hWnd;
}
auto tab = static_cast<dom::TabChild*>(ipcDoc->Manager());
MOZ_ASSERT(tab);
return reinterpret_cast<HWND>(tab->GetNativeWindowHandle());

View file

@ -85,6 +85,10 @@ a11y::ProxyDestroyed(ProxyAccessible* aProxy)
if (!wrapper)
return;
if (aProxy->IsDoc() && nsWinUtils::IsWindowEmulationStarted()) {
aProxy->AsDoc()->SetEmulatedWindowHandle(nullptr);
}
wrapper->Shutdown();
aProxy->SetWrapper(0);
wrapper->Release();

View file

@ -14,6 +14,7 @@ EXPORTS.mozilla.a11y += [
'HyperTextAccessibleWrap.h',
'IDSet.h',
'MsaaIdGenerator.h',
'nsWinUtils.h',
]
UNIFIED_SOURCES += [

View file

@ -12,6 +12,7 @@
#include "nsAccessibilityService.h"
#include "nsCoreUtils.h"
#include "mozilla/a11y/DocAccessibleParent.h"
#include "mozilla/Preferences.h"
#include "nsArrayUtils.h"
#include "nsIArray.h"
@ -20,6 +21,7 @@
#include "nsIDocShellTreeItem.h"
#include "mozilla/dom/Element.h"
#include "nsXULAppAPI.h"
#include "ProxyWrappers.h"
using namespace mozilla;
using namespace mozilla::a11y;
@ -153,18 +155,25 @@ WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
// for details).
int32_t objId = static_cast<DWORD>(lParam);
if (objId == OBJID_CLIENT) {
IAccessible* msaaAccessible = nullptr;
DocAccessible* document =
reinterpret_cast<DocAccessible*>(::GetPropW(hWnd, kPropNameDocAcc));
if (document) {
IAccessible* msaaAccessible = nullptr;
document->GetNativeInterface((void**)&msaaAccessible); // does an addref
if (msaaAccessible) {
LRESULT result = ::LresultFromObject(IID_IAccessible, wParam,
msaaAccessible); // does an addref
msaaAccessible->Release(); // release extra addref
return result;
} else {
DocAccessibleParent* docParent = static_cast<DocAccessibleParent*>(
::GetPropW(hWnd, kPropNameDocAccParent));
if (docParent) {
auto wrapper = WrapperFor(docParent);
wrapper->GetNativeInterface((void**)&msaaAccessible); // does an addref
}
}
if (msaaAccessible) {
LRESULT result = ::LresultFromObject(IID_IAccessible, wParam,
msaaAccessible); // does an addref
msaaAccessible->Release(); // release extra addref
return result;
}
}
return 0;
}

View file

@ -23,6 +23,7 @@ class DocAccessible;
const LPCWSTR kClassNameRoot = L"MozillaUIWindowClass";
const LPCWSTR kClassNameTabContent = L"MozillaContentWindowClass";
const LPCWSTR kPropNameDocAcc = L"MozDocAccessible";
const LPCWSTR kPropNameDocAccParent = L"MozDocAccessibleParent";
class nsWinUtils
{

View file

@ -102,6 +102,7 @@
#if defined(XP_WIN) && defined(ACCESSIBILITY)
#include "mozilla/a11y/AccessibleWrap.h"
#include "mozilla/a11y/nsWinUtils.h"
#endif
using namespace mozilla::dom;
@ -269,6 +270,16 @@ TabParent::SetOwnerElement(Element* aElement)
reinterpret_cast<uintptr_t>(widget->GetNativeData(NS_NATIVE_WINDOW));
}
Unused << SendUpdateNativeWindowHandle(newWindowHandle);
a11y::DocAccessibleParent* doc = GetTopLevelDocAccessible();
if (doc) {
HWND hWnd = reinterpret_cast<HWND>(doc->GetEmulatedWindowHandle());
if (hWnd) {
HWND parentHwnd = reinterpret_cast<HWND>(newWindowHandle);
if (parentHwnd != ::GetParent(hWnd)) {
::SetParent(hWnd, parentHwnd);
}
}
}
}
#endif
@ -921,6 +932,9 @@ TabParent::RecvPDocAccessibleConstructor(PDocAccessibleParent* aDoc,
MOZ_ASSERT(aDocCOMProxy.IsNull());
if (added) {
a11y::WrapperFor(doc)->SetID(aMsaaID);
if (a11y::nsWinUtils::IsWindowEmulationStarted()) {
doc->SetEmulatedWindowHandle(parentDoc->GetEmulatedWindowHandle());
}
}
#endif
if (!added) {