mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-07 18:04:46 +00:00
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
commit
207b516e89
@ -18,9 +18,7 @@ StyleInfo::StyleInfo(dom::Element* aElement, nsIPresShell* aPresShell) :
|
||||
mElement(aElement)
|
||||
{
|
||||
mStyleContext =
|
||||
nsComputedDOMStyle::GetStyleContextForElementNoFlush(aElement,
|
||||
nullptr,
|
||||
aPresShell);
|
||||
nsComputedDOMStyle::GetStyleContextNoFlush(aElement, nullptr, aPresShell);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -25,6 +25,8 @@
|
||||
#define __XMLDocument_FWD_DEFINED__
|
||||
#endif // !defined(__XMLDocument_FWD_DEFINED__)
|
||||
|
||||
#include <combaseapi.h>
|
||||
|
||||
#include "mozilla/a11y/COMPtrTypes.h"
|
||||
|
||||
// This define in rpcndr.h messes up our code, so we must undefine it after
|
||||
@ -39,6 +41,7 @@ namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
typedef uint32_t IAccessibleHolder;
|
||||
typedef uint32_t IHandlerControlHolder;
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
@ -6,13 +6,19 @@
|
||||
|
||||
#include "mozilla/a11y/COMPtrTypes.h"
|
||||
|
||||
#include "Accessible2_3.h"
|
||||
#include "MainThreadUtils.h"
|
||||
#include "mozilla/a11y/Accessible.h"
|
||||
#include "mozilla/a11y/HandlerProvider.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/mscom/MainThreadHandoff.h"
|
||||
#include "mozilla/mscom/Utils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
using mozilla::mscom::MainThreadHandoff;
|
||||
using mozilla::mscom::ProxyUniquePtr;
|
||||
using mozilla::mscom::STAUniquePtr;
|
||||
|
||||
namespace mozilla {
|
||||
@ -26,24 +32,44 @@ CreateHolderFromAccessible(Accessible* aAccToWrap)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IAccessible* rawNative = nullptr;
|
||||
aAccToWrap->GetNativeInterface((void**)&rawNative);
|
||||
MOZ_ASSERT(rawNative);
|
||||
if (!rawNative) {
|
||||
STAUniquePtr<IAccessible> iaToProxy;
|
||||
aAccToWrap->GetNativeInterface(mscom::getter_AddRefs(iaToProxy));
|
||||
MOZ_ASSERT(iaToProxy);
|
||||
if (!iaToProxy) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
STAUniquePtr<IAccessible> iaToProxy(rawNative);
|
||||
static const bool useHandler =
|
||||
Preferences::GetBool("accessibility.handler.enabled", false);
|
||||
|
||||
IAccessible* rawIntercepted = nullptr;
|
||||
HRESULT hr = MainThreadHandoff::WrapInterface(Move(iaToProxy), &rawIntercepted);
|
||||
RefPtr<HandlerProvider> payload;
|
||||
if (useHandler) {
|
||||
payload = new HandlerProvider(IID_IAccessible,
|
||||
mscom::ToInterceptorTargetPtr(iaToProxy));
|
||||
}
|
||||
|
||||
ProxyUniquePtr<IAccessible> intercepted;
|
||||
HRESULT hr = MainThreadHandoff::WrapInterface(Move(iaToProxy), payload,
|
||||
(IAccessible**) mscom::getter_AddRefs(intercepted));
|
||||
MOZ_ASSERT(SUCCEEDED(hr));
|
||||
if (FAILED(hr)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IAccessibleHolder::COMPtrType iaIntercepted(rawIntercepted);
|
||||
return IAccessibleHolder(Move(iaIntercepted));
|
||||
return IAccessibleHolder(Move(intercepted));
|
||||
}
|
||||
|
||||
IHandlerControlHolder
|
||||
CreateHolderFromHandlerControl(mscom::ProxyUniquePtr<IHandlerControl> aHandlerControl)
|
||||
{
|
||||
MOZ_ASSERT(aHandlerControl);
|
||||
MOZ_ASSERT(XRE_IsContentProcess());
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!aHandlerControl) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return IHandlerControlHolder(Move(aHandlerControl));
|
||||
}
|
||||
|
||||
} // namespace a11y
|
||||
|
@ -7,6 +7,7 @@
|
||||
#ifndef mozilla_a11y_COMPtrTypes_h
|
||||
#define mozilla_a11y_COMPtrTypes_h
|
||||
|
||||
#include "mozilla/a11y/AccessibleHandler.h"
|
||||
#include "mozilla/mscom/COMPtrHolder.h"
|
||||
|
||||
#include <oleacc.h>
|
||||
@ -21,6 +22,11 @@ class Accessible;
|
||||
IAccessibleHolder
|
||||
CreateHolderFromAccessible(Accessible* aAccToWrap);
|
||||
|
||||
typedef mozilla::mscom::COMPtrHolder<IHandlerControl, IID_IHandlerControl> IHandlerControlHolder;
|
||||
|
||||
IHandlerControlHolder
|
||||
CreateHolderFromHandlerControl(mscom::ProxyUniquePtr<IHandlerControl> aHandlerControl);
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
|
263
accessible/ipc/win/HandlerProvider.cpp
Normal file
263
accessible/ipc/win/HandlerProvider.cpp
Normal file
@ -0,0 +1,263 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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/. */
|
||||
|
||||
#define INITGUID
|
||||
|
||||
#include "mozilla/a11y/HandlerProvider.h"
|
||||
|
||||
#include "Accessible2_3.h"
|
||||
#include "HandlerData.h"
|
||||
#include "HandlerData_i.c"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/a11y/AccessibleWrap.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/mscom/AgileReference.h"
|
||||
#include "mozilla/mscom/MainThreadInvoker.h"
|
||||
#include "mozilla/mscom/Ptr.h"
|
||||
#include "mozilla/mscom/StructStream.h"
|
||||
#include "mozilla/mscom/Utils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#include <memory.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
HandlerProvider::HandlerProvider(REFIID aIid,
|
||||
mscom::InterceptorTargetPtr<IUnknown> aTarget)
|
||||
: mRefCnt(0)
|
||||
, mMutex("mozilla::a11y::HandlerProvider::mMutex")
|
||||
, mTargetUnkIid(aIid)
|
||||
, mTargetUnk(Move(aTarget))
|
||||
{
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerProvider::QueryInterface(REFIID riid, void** ppv)
|
||||
{
|
||||
if (!ppv) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
RefPtr<IUnknown> punk;
|
||||
|
||||
if (riid == IID_IUnknown || riid == IID_IGeckoBackChannel) {
|
||||
punk = static_cast<IGeckoBackChannel*>(this);
|
||||
}
|
||||
|
||||
if (!punk) {
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
punk.forget(ppv);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
ULONG
|
||||
HandlerProvider::AddRef()
|
||||
{
|
||||
return ++mRefCnt;
|
||||
}
|
||||
|
||||
ULONG
|
||||
HandlerProvider::Release()
|
||||
{
|
||||
ULONG result = --mRefCnt;
|
||||
if (!result) {
|
||||
delete this;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerProvider::GetHandler(NotNull<CLSID*> aHandlerClsid)
|
||||
{
|
||||
if (!IsTargetInterfaceCacheable()) {
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
*aHandlerClsid = CLSID_AccessibleHandler;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void
|
||||
HandlerProvider::GetAndSerializePayload(const MutexAutoLock&)
|
||||
{
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
|
||||
if (mSerializer) {
|
||||
return;
|
||||
}
|
||||
|
||||
IA2Payload payload{};
|
||||
|
||||
if (!mscom::InvokeOnMainThread(this, &HandlerProvider::BuildIA2Data,
|
||||
&payload.mData) ||
|
||||
!payload.mData.mUniqueId) {
|
||||
return;
|
||||
}
|
||||
|
||||
// But we set mGeckoBackChannel on the current thread which resides in the
|
||||
// MTA. This is important to ensure that COM always invokes
|
||||
// IGeckoBackChannel methods in an MTA background thread.
|
||||
|
||||
RefPtr<IGeckoBackChannel> payloadRef(this);
|
||||
// AddRef/Release pair for this reference is handled by payloadRef
|
||||
payload.mGeckoBackChannel = this;
|
||||
|
||||
mSerializer = MakeUnique<mscom::StructToStream>(payload, &IA2Payload_Encode);
|
||||
|
||||
// Now that we have serialized payload, we should free any BSTRs that were
|
||||
// allocated in BuildIA2Data.
|
||||
ClearIA2Data(payload.mData);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerProvider::GetHandlerPayloadSize(NotNull<DWORD*> aOutPayloadSize)
|
||||
{
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
|
||||
if (!IsTargetInterfaceCacheable()) {
|
||||
*aOutPayloadSize = mscom::StructToStream::GetEmptySize();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
GetAndSerializePayload(lock);
|
||||
|
||||
if (!mSerializer) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
*aOutPayloadSize = mSerializer->GetSize();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void
|
||||
HandlerProvider::BuildIA2Data(IA2Data* aOutIA2Data)
|
||||
{
|
||||
MOZ_ASSERT(aOutIA2Data);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mTargetUnk);
|
||||
MOZ_ASSERT(IsTargetInterfaceCacheable());
|
||||
|
||||
RefPtr<NEWEST_IA2_INTERFACE>
|
||||
target(static_cast<NEWEST_IA2_INTERFACE*>(mTargetUnk.get()));
|
||||
|
||||
// NB: get_uniqueID should be the final property retrieved in this method,
|
||||
// as its presence is used to determine whether the rest of this data
|
||||
// retrieval was successful.
|
||||
HRESULT hr = target->get_uniqueID(&aOutIA2Data->mUniqueId);
|
||||
if (FAILED(hr)) {
|
||||
ClearIA2Data(*aOutIA2Data);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HandlerProvider::ClearIA2Data(IA2Data& aData)
|
||||
{
|
||||
ZeroMemory(&aData, sizeof(IA2Data));
|
||||
}
|
||||
|
||||
bool
|
||||
HandlerProvider::IsTargetInterfaceCacheable()
|
||||
{
|
||||
return MarshalAs(mTargetUnkIid) == NEWEST_IA2_IID;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerProvider::WriteHandlerPayload(NotNull<IStream*> aStream)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
if (!mSerializer) {
|
||||
mscom::StructToStream emptyStruct;
|
||||
return emptyStruct.Write(aStream);
|
||||
}
|
||||
|
||||
HRESULT hr = mSerializer->Write(aStream);
|
||||
|
||||
mSerializer.reset();
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
REFIID
|
||||
HandlerProvider::MarshalAs(REFIID aIid)
|
||||
{
|
||||
static_assert(&NEWEST_IA2_IID == &IID_IAccessible2_3,
|
||||
"You have modified NEWEST_IA2_IID. This code needs updating.");
|
||||
if (aIid == IID_IDispatch || aIid == IID_IAccessible ||
|
||||
aIid == IID_IAccessible2 || aIid == IID_IAccessible2_2 ||
|
||||
aIid == IID_IAccessible2_3) {
|
||||
// This should always be the newest IA2 interface ID
|
||||
return NEWEST_IA2_IID;
|
||||
}
|
||||
// Otherwise we juse return the identity.
|
||||
return aIid;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerProvider::NewInstance(REFIID aIid,
|
||||
mscom::InterceptorTargetPtr<IUnknown> aTarget,
|
||||
NotNull<mscom::IHandlerProvider**> aOutNewPayload)
|
||||
{
|
||||
RefPtr<IHandlerProvider> newPayload(new HandlerProvider(aIid, Move(aTarget)));
|
||||
newPayload.forget(aOutNewPayload.get());
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void
|
||||
HandlerProvider::SetHandlerControlOnMainThread(DWORD aPid,
|
||||
mscom::ProxyUniquePtr<IHandlerControl> aCtrl)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
auto content = dom::ContentChild::GetSingleton();
|
||||
MOZ_ASSERT(content);
|
||||
|
||||
IHandlerControlHolder holder(CreateHolderFromHandlerControl(Move(aCtrl)));
|
||||
Unused << content->SendA11yHandlerControl(aPid, holder);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerProvider::put_HandlerControl(long aPid, IHandlerControl* aCtrl)
|
||||
{
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
|
||||
if (!aCtrl) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
auto ptrProxy = mscom::ToProxyUniquePtr(aCtrl);
|
||||
|
||||
if (!mscom::InvokeOnMainThread(this,
|
||||
&HandlerProvider::SetHandlerControlOnMainThread,
|
||||
static_cast<DWORD>(aPid), Move(ptrProxy))) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerProvider::Refresh(IA2Data* aOutData)
|
||||
{
|
||||
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
|
||||
|
||||
if (!mscom::InvokeOnMainThread(this, &HandlerProvider::BuildIA2Data,
|
||||
aOutData)) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
75
accessible/ipc/win/HandlerProvider.h
Normal file
75
accessible/ipc/win/HandlerProvider.h
Normal file
@ -0,0 +1,75 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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_HandlerProvider_h
|
||||
#define mozilla_a11y_HandlerProvider_h
|
||||
|
||||
#include "handler/AccessibleHandler.h"
|
||||
#include "mozilla/AlreadyAddRefed.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/mscom/IHandlerProvider.h"
|
||||
#include "mozilla/mscom/Ptr.h"
|
||||
#include "mozilla/mscom/StructStream.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
struct NEWEST_IA2_INTERFACE;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace mscom {
|
||||
|
||||
class StructToStream;
|
||||
|
||||
} // namespace mscom
|
||||
|
||||
namespace a11y {
|
||||
|
||||
class HandlerProvider final : public IGeckoBackChannel
|
||||
, public mscom::IHandlerProvider
|
||||
{
|
||||
public:
|
||||
HandlerProvider(REFIID aIid, mscom::InterceptorTargetPtr<IUnknown> aTarget);
|
||||
|
||||
// IUnknown
|
||||
STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
|
||||
STDMETHODIMP_(ULONG) AddRef() override;
|
||||
STDMETHODIMP_(ULONG) Release() override;
|
||||
|
||||
// IHandlerProvider
|
||||
STDMETHODIMP GetHandler(NotNull<CLSID*> aHandlerClsid) override;
|
||||
STDMETHODIMP GetHandlerPayloadSize(NotNull<DWORD*> aOutPayloadSize) override;
|
||||
STDMETHODIMP WriteHandlerPayload(NotNull<IStream*> aStream) override;
|
||||
STDMETHODIMP_(REFIID) MarshalAs(REFIID aIid) override;
|
||||
STDMETHODIMP NewInstance(REFIID aIid,
|
||||
mscom::InterceptorTargetPtr<IUnknown> aTarget,
|
||||
NotNull<mscom::IHandlerProvider**> aOutNewPayload) override;
|
||||
|
||||
// IGeckoBackChannel
|
||||
STDMETHODIMP put_HandlerControl(long aPid, IHandlerControl* aCtrl) override;
|
||||
STDMETHODIMP Refresh(IA2Data* aOutData) override;
|
||||
|
||||
private:
|
||||
~HandlerProvider() = default;
|
||||
|
||||
void SetHandlerControlOnMainThread(DWORD aPid,
|
||||
mscom::ProxyUniquePtr<IHandlerControl> aCtrl);
|
||||
void GetAndSerializePayload(const MutexAutoLock&);
|
||||
void BuildIA2Data(IA2Data* aOutIA2Data);
|
||||
static void ClearIA2Data(IA2Data& aData);
|
||||
bool IsTargetInterfaceCacheable();
|
||||
|
||||
Atomic<uint32_t> mRefCnt;
|
||||
Mutex mMutex; // Protects mSerializer
|
||||
REFIID mTargetUnkIid;
|
||||
mscom::InterceptorTargetPtr<IUnknown> mTargetUnk; // Constant, main thread only
|
||||
UniquePtr<mscom::StructToStream> mSerializer;
|
||||
};
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_a11y_HandlerProvider_h
|
1008
accessible/ipc/win/handler/AccessibleHandler.cpp
Normal file
1008
accessible/ipc/win/handler/AccessibleHandler.cpp
Normal file
File diff suppressed because it is too large
Load Diff
10
accessible/ipc/win/handler/AccessibleHandler.def
Normal file
10
accessible/ipc/win/handler/AccessibleHandler.def
Normal file
@ -0,0 +1,10 @@
|
||||
;+# 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/.
|
||||
|
||||
LIBRARY AccessibleHandler.dll
|
||||
|
||||
EXPORTS DllGetClassObject PRIVATE
|
||||
DllCanUnloadNow PRIVATE
|
||||
DllRegisterServer PRIVATE
|
||||
DllUnregisterServer PRIVATE
|
195
accessible/ipc/win/handler/AccessibleHandler.h
Normal file
195
accessible/ipc/win/handler/AccessibleHandler.h
Normal file
@ -0,0 +1,195 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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_AccessibleHandler_h
|
||||
#define mozilla_a11y_AccessibleHandler_h
|
||||
|
||||
#define NEWEST_IA2_BASENAME Accessible2_3
|
||||
|
||||
#define __QUOTE(idl) #idl
|
||||
#define __GENIDL(base) __QUOTE(base##.idl)
|
||||
#define IDLFOR(base) __GENIDL(base)
|
||||
#define NEWEST_IA2_IDL IDLFOR(NEWEST_IA2_BASENAME)
|
||||
|
||||
#define __GENIFACE(base) I##base
|
||||
#define INTERFACEFOR(base) __GENIFACE(base)
|
||||
#define NEWEST_IA2_INTERFACE INTERFACEFOR(NEWEST_IA2_BASENAME)
|
||||
|
||||
#define __GENIID(iface) IID_##iface
|
||||
#define IIDFOR(iface) __GENIID(iface)
|
||||
#define NEWEST_IA2_IID IIDFOR(NEWEST_IA2_INTERFACE)
|
||||
|
||||
#if defined(__midl)
|
||||
|
||||
import NEWEST_IA2_IDL;
|
||||
|
||||
#else
|
||||
|
||||
#include "HandlerData.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#if !defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
#include "Accessible2_3.h"
|
||||
#include "Handler.h"
|
||||
#include "mozilla/mscom/StructStream.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
#include <ocidl.h>
|
||||
#include <servprov.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
class AccessibleHandler final : public mscom::Handler
|
||||
, public NEWEST_IA2_INTERFACE
|
||||
, public IServiceProvider
|
||||
, public IProvideClassInfo
|
||||
{
|
||||
public:
|
||||
static HRESULT Create(IUnknown* aOuter, REFIID aIid, void** aOutInterface);
|
||||
|
||||
// mscom::Handler
|
||||
HRESULT QueryHandlerInterface(IUnknown* aProxyUnknown, REFIID aIid,
|
||||
void** aOutInterface) override;
|
||||
HRESULT ReadHandlerPayload(IStream* aStream, REFIID aIid) override;
|
||||
|
||||
REFIID MarshalAs(REFIID aRequestedIid) override;
|
||||
HRESULT GetHandlerPayloadSize(REFIID aIid, DWORD* aOutPayloadSize) override;
|
||||
HRESULT WriteHandlerPayload(IStream* aStream, REFIID aIId) override;
|
||||
|
||||
// IUnknown
|
||||
STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
|
||||
STDMETHODIMP_(ULONG) AddRef() override;
|
||||
STDMETHODIMP_(ULONG) Release() override;
|
||||
|
||||
// IDispatch
|
||||
STDMETHODIMP GetTypeInfoCount(UINT *pctinfo) override;
|
||||
STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) override;
|
||||
STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames,
|
||||
LCID lcid, DISPID *rgDispId) override;
|
||||
STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
|
||||
DISPPARAMS *pDispParams, VARIANT *pVarResult,
|
||||
EXCEPINFO *pExcepInfo, UINT *puArgErr) override;
|
||||
|
||||
// IAccessible
|
||||
STDMETHODIMP get_accParent(IDispatch **ppdispParent) override;
|
||||
STDMETHODIMP get_accChildCount(long *pcountChildren) override;
|
||||
STDMETHODIMP get_accChild(VARIANT varChild, IDispatch **ppdispChild) override;
|
||||
STDMETHODIMP get_accName(VARIANT varChild, BSTR *pszName) override;
|
||||
STDMETHODIMP get_accValue(VARIANT varChild, BSTR *pszValue) override;
|
||||
STDMETHODIMP get_accDescription(VARIANT varChild, BSTR *pszDescription) override;
|
||||
STDMETHODIMP get_accRole(VARIANT varChild, VARIANT *pvarRole) override;
|
||||
STDMETHODIMP get_accState(VARIANT varChild, VARIANT *pvarState) override;
|
||||
STDMETHODIMP get_accHelp(VARIANT varChild, BSTR *pszHelp) override;
|
||||
STDMETHODIMP get_accHelpTopic(BSTR *pszHelpFile, VARIANT varChild,
|
||||
long *pidTopic) override;
|
||||
STDMETHODIMP get_accKeyboardShortcut(VARIANT varChild,
|
||||
BSTR *pszKeyboardShortcut) override;
|
||||
STDMETHODIMP get_accFocus(VARIANT *pvarChild) override;
|
||||
STDMETHODIMP get_accSelection(VARIANT *pvarChildren) override;
|
||||
STDMETHODIMP get_accDefaultAction(VARIANT varChild,
|
||||
BSTR *pszDefaultAction) override;
|
||||
STDMETHODIMP accSelect(long flagsSelect, VARIANT varChild) override;
|
||||
STDMETHODIMP accLocation(long *pxLeft, long *pyTop, long *pcxWidth,
|
||||
long *pcyHeight, VARIANT varChild) override;
|
||||
STDMETHODIMP accNavigate(long navDir, VARIANT varStart,
|
||||
VARIANT *pvarEndUpAt) override;
|
||||
STDMETHODIMP accHitTest( long xLeft, long yTop, VARIANT *pvarChild) override;
|
||||
STDMETHODIMP accDoDefaultAction(VARIANT varChild) override;
|
||||
STDMETHODIMP put_accName(VARIANT varChild, BSTR szName) override;
|
||||
STDMETHODIMP put_accValue(VARIANT varChild, BSTR szValue) override;
|
||||
|
||||
// IAccessible2
|
||||
STDMETHODIMP get_nRelations(long* nRelations) override;
|
||||
STDMETHODIMP get_relation(long relationIndex,
|
||||
IAccessibleRelation** relation) override;
|
||||
STDMETHODIMP get_relations(long maxRelations, IAccessibleRelation** relations,
|
||||
long* nRelations) override;
|
||||
STDMETHODIMP role(long* role) override;
|
||||
STDMETHODIMP scrollTo(IA2ScrollType scrollType) override;
|
||||
STDMETHODIMP scrollToPoint(IA2CoordinateType coordinateType, long x,
|
||||
long y) override;
|
||||
STDMETHODIMP get_groupPosition(long* groupLevel, long* similarItemsInGroup,
|
||||
long* positionInGroup) override;
|
||||
STDMETHODIMP get_states(AccessibleStates* states) override;
|
||||
STDMETHODIMP get_extendedRole(BSTR* extendedRole) override;
|
||||
STDMETHODIMP get_localizedExtendedRole(BSTR* localizedExtendedRole) override;
|
||||
STDMETHODIMP get_nExtendedStates(long* nExtendedStates) override;
|
||||
STDMETHODIMP get_extendedStates(long maxExtendedStates, BSTR** extendedStates,
|
||||
long* nExtendedStates) override;
|
||||
STDMETHODIMP get_localizedExtendedStates(long maxLocalizedExtendedStates,
|
||||
BSTR** localizedExtendedStates,
|
||||
long* nLocalizedExtendedStates) override;
|
||||
STDMETHODIMP get_uniqueID(long* uniqueID) override;
|
||||
STDMETHODIMP get_windowHandle(HWND* windowHandle) override;
|
||||
STDMETHODIMP get_indexInParent(long* indexInParent) override;
|
||||
STDMETHODIMP get_locale(IA2Locale* locale) override;
|
||||
STDMETHODIMP get_attributes(BSTR* attributes) override;
|
||||
|
||||
// IAccessible2_2
|
||||
STDMETHODIMP get_attribute(BSTR name, VARIANT* attribute) override;
|
||||
STDMETHODIMP get_accessibleWithCaret(IUnknown** accessible,
|
||||
long* caretOffset) override;
|
||||
STDMETHODIMP get_relationTargetsOfType(BSTR type, long maxTargets,
|
||||
IUnknown*** targets,
|
||||
long* nTargets) override;
|
||||
|
||||
// IAccessible2_3
|
||||
STDMETHODIMP get_selectionRanges(IA2Range** ranges, long* nRanges) override;
|
||||
|
||||
// IServiceProvider
|
||||
STDMETHODIMP QueryService(REFGUID aServiceId, REFIID aIid,
|
||||
void** aOutInterface) override;
|
||||
|
||||
// IProvideClassInfo
|
||||
STDMETHODIMP GetClassInfo(ITypeInfo** aOutTypeInfo) override;
|
||||
|
||||
private:
|
||||
AccessibleHandler(IUnknown* aOuter, HRESULT* aResult);
|
||||
virtual ~AccessibleHandler();
|
||||
|
||||
HRESULT ResolveIA2();
|
||||
HRESULT ResolveIDispatch();
|
||||
HRESULT MaybeUpdateCachedData();
|
||||
|
||||
RefPtr<IUnknown> mDispatchUnk;
|
||||
/**
|
||||
* Handlers aggregate their proxies. This means that their proxies delegate
|
||||
* their IUnknown implementation to us.
|
||||
*
|
||||
* mDispatchUnk and the result of Handler::GetProxy() are both strong
|
||||
* references to the aggregated objects. OTOH, any interfaces that are QI'd
|
||||
* from those aggregated objects have delegated unknowns.
|
||||
*
|
||||
* AddRef'ing an interface with a delegated unknown ends up incrementing the
|
||||
* refcount of the *aggregator*. Since we are the aggregator of mDispatchUnk
|
||||
* and of the wrapped proxy, holding a strong reference to any interfaces
|
||||
* QI'd off of those objects would create a reference cycle.
|
||||
*
|
||||
* We may hold onto pointers to those references, but when we query them we
|
||||
* must immediately Release() them to prevent these cycles.
|
||||
*
|
||||
* It is safe for us to use these raw pointers because the aggregated
|
||||
* objects's lifetimes are proper subsets of our own lifetime.
|
||||
*/
|
||||
IDispatch* mDispatch; // weak
|
||||
NEWEST_IA2_INTERFACE* mIA2PassThru; // weak
|
||||
IServiceProvider* mServProvPassThru; // weak
|
||||
IA2Payload mCachedData;
|
||||
UniquePtr<mscom::StructToStream> mSerializer;
|
||||
uint32_t mCacheGen;
|
||||
};
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // !defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
#endif // defined(__midl)
|
||||
|
||||
#endif // mozilla_a11y_AccessibleHandler_h
|
5
accessible/ipc/win/handler/AccessibleHandler.rc
Normal file
5
accessible/ipc/win/handler/AccessibleHandler.rc
Normal file
@ -0,0 +1,5 @@
|
||||
/* 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/. */
|
||||
|
||||
1 typelib HandlerData.tlb
|
98
accessible/ipc/win/handler/AccessibleHandlerControl.cpp
Normal file
98
accessible/ipc/win/handler/AccessibleHandlerControl.cpp
Normal file
@ -0,0 +1,98 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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/. */
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
#error This code is NOT for internal Gecko use!
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
#include "AccessibleHandlerControl.h"
|
||||
|
||||
#include "AccessibleHandler.h"
|
||||
|
||||
#include "AccessibleEventId.h"
|
||||
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
mscom::SingletonFactory<AccessibleHandlerControl> gControlFactory;
|
||||
|
||||
HRESULT
|
||||
AccessibleHandlerControl::Create(AccessibleHandlerControl** aOutObject)
|
||||
{
|
||||
if (!aOutObject) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
RefPtr<AccessibleHandlerControl> ctl(new AccessibleHandlerControl());
|
||||
ctl.forget(aOutObject);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
AccessibleHandlerControl::AccessibleHandlerControl()
|
||||
: mRefCnt(0)
|
||||
, mCacheGen(0)
|
||||
, mIA2Proxy(mscom::RegisterProxy(L"ia2marshal.dll"))
|
||||
, mHandlerProxy(mscom::RegisterProxy())
|
||||
{
|
||||
MOZ_ASSERT(mIA2Proxy);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleHandlerControl::QueryInterface(REFIID aIid, void** aOutInterface)
|
||||
{
|
||||
if (!aOutInterface) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (aIid == IID_IUnknown || aIid == IID_IHandlerControl) {
|
||||
RefPtr<IHandlerControl> ctl(this);
|
||||
ctl.forget(aOutInterface);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
*aOutInterface = nullptr;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
ULONG
|
||||
AccessibleHandlerControl::AddRef()
|
||||
{
|
||||
return ++mRefCnt;
|
||||
}
|
||||
|
||||
ULONG
|
||||
AccessibleHandlerControl::Release()
|
||||
{
|
||||
ULONG result = --mRefCnt;
|
||||
if (!result) {
|
||||
delete this;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleHandlerControl::Invalidate()
|
||||
{
|
||||
++mCacheGen;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleHandlerControl::GetHandlerTypeInfo(ITypeInfo** aOutTypeInfo)
|
||||
{
|
||||
if (!mHandlerProxy) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
return mHandlerProxy->GetTypeInfoForGuid(CLSID_AccessibleHandler,
|
||||
aOutTypeInfo);
|
||||
}
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
56
accessible/ipc/win/handler/AccessibleHandlerControl.h
Normal file
56
accessible/ipc/win/handler/AccessibleHandlerControl.h
Normal file
@ -0,0 +1,56 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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/. */
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
#error This code is NOT for internal Gecko use!
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
#ifndef mozilla_a11y_AccessibleHandlerControl_h
|
||||
#define mozilla_a11y_AccessibleHandlerControl_h
|
||||
|
||||
#include "Factory.h"
|
||||
#include "HandlerData.h"
|
||||
#include "mozilla/mscom/Registration.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
class AccessibleHandlerControl final : public IHandlerControl
|
||||
{
|
||||
public:
|
||||
static HRESULT Create(AccessibleHandlerControl** aOutObject);
|
||||
|
||||
// IUnknown
|
||||
STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
|
||||
STDMETHODIMP_(ULONG) AddRef() override;
|
||||
STDMETHODIMP_(ULONG) Release() override;
|
||||
|
||||
// IHandlerControl
|
||||
STDMETHODIMP Invalidate() override;
|
||||
|
||||
uint32_t GetCacheGen() const
|
||||
{
|
||||
return mCacheGen;
|
||||
}
|
||||
|
||||
HRESULT GetHandlerTypeInfo(ITypeInfo** aOutTypeInfo);
|
||||
|
||||
private:
|
||||
AccessibleHandlerControl();
|
||||
~AccessibleHandlerControl() = default;
|
||||
|
||||
ULONG mRefCnt;
|
||||
uint32_t mCacheGen;
|
||||
UniquePtr<mscom::RegisteredProxy> mIA2Proxy;
|
||||
UniquePtr<mscom::RegisteredProxy> mHandlerProxy;
|
||||
};
|
||||
|
||||
extern mscom::SingletonFactory<AccessibleHandlerControl> gControlFactory;
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_a11y_AccessibleHandlerControl_h
|
11
accessible/ipc/win/handler/HandlerData.acf
Normal file
11
accessible/ipc/win/handler/HandlerData.acf
Normal file
@ -0,0 +1,11 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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/. */
|
||||
|
||||
[explicit_handle]
|
||||
interface HandlerData
|
||||
{
|
||||
typedef [encode,decode] IA2Payload;
|
||||
}
|
119
accessible/ipc/win/handler/HandlerData.idl
Normal file
119
accessible/ipc/win/handler/HandlerData.idl
Normal file
@ -0,0 +1,119 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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 "AccessibleHandler.h"
|
||||
|
||||
import "ocidl.idl";
|
||||
import "ServProv.idl";
|
||||
|
||||
typedef struct _IA2Data
|
||||
{
|
||||
long mUniqueId;
|
||||
} IA2Data;
|
||||
|
||||
interface IGeckoBackChannel;
|
||||
|
||||
// We define different CLSIDs and IIDs depending on channel and officiality.
|
||||
// This prevents handlers from installing overtop one another when multiple
|
||||
// channels are present. Note that we do not do this for all UUIDs in this IDL,
|
||||
// just the ones that are written to the registry (coclass and interfaces that
|
||||
// have the [object] annotation)
|
||||
#if !defined(MOZ_OFFICIAL_BRANDING)
|
||||
|
||||
# if defined(DEBUG)
|
||||
|
||||
// Local debug builds
|
||||
# define HANDLER_CLSID 398ffd8d-5382-48f7-9e3b-19012762d39a
|
||||
# define IHANDLERCONTROL_IID a218497e-8b10-460b-b668-a92b7ee39ff2
|
||||
# define ASYNCIHANDLERCONTROL_IID ca18b9ab-04b6-41be-87f7-d99913d6a2e8
|
||||
# define IGECKOBACKCHANNEL_IID 231c4946-4479-4c8e-aadc-8a0e48fc4c51
|
||||
|
||||
# else
|
||||
|
||||
// Local non-debug builds
|
||||
# define HANDLER_CLSID ce573faf-7815-4fc2-a031-b092268ace9e
|
||||
# define IHANDLERCONTROL_IID 2b715cce-1790-4fe1-aef5-48bb5acdf3a1
|
||||
# define ASYNCIHANDLERCONTROL_IID 8e089670-4f57-41a7-89c0-37f17482fa6f
|
||||
# define IGECKOBACKCHANNEL_IID 18e2488d-310f-400f-8339-0e50b513e801
|
||||
|
||||
# endif
|
||||
|
||||
#elif defined(NIGHTLY_BUILD)
|
||||
|
||||
// Official Nightly
|
||||
# define IHANDLERCONTROL_IID c57343fc-e011-40c2-b748-da82eabf0f1f
|
||||
# define ASYNCIHANDLERCONTROL_IID 648c92a1-ea35-46da-a806-6b55c6247373
|
||||
# define HANDLER_CLSID 4629216b-8753-41bf-9527-5bff51401671
|
||||
# define IGECKOBACKCHANNEL_IID e61e038d-40dd-464a-9aba-66b206b6911b
|
||||
|
||||
#elif defined(RELEASE_OR_BETA)
|
||||
|
||||
// Official Beta and Official Release
|
||||
# define IHANDLERCONTROL_IID ce30f77e-8847-44f0-a648-a9656bd89c0d
|
||||
# define ASYNCIHANDLERCONTROL_IID dca8d857-1a63-4045-8f36-8809eb093d04
|
||||
# define HANDLER_CLSID 1baa303d-b4b9-45e5-9ccb-e3fca3e274b6
|
||||
# define IGECKOBACKCHANNEL_IID b32983ff-ef84-4945-8f86-fb7491b4f57b
|
||||
|
||||
#else
|
||||
|
||||
// Official Aurora
|
||||
# define IHANDLERCONTROL_IID 3316ce35-f892-4832-97c5-06c52c03cdba
|
||||
# define ASYNCIHANDLERCONTROL_IID 15b48b76-ad38-4ad3-bd1a-d3c48a5a9947
|
||||
# define HANDLER_CLSID 4a195748-dca2-45fb-9295-0a139e76a9e7
|
||||
# define IGECKOBACKCHANNEL_IID dd2e4a89-999e-4d65-8b65-440c923ddb61
|
||||
|
||||
#endif
|
||||
|
||||
[uuid(2b0e83b3-fd1a-443f-9ed6-c00d39055b58)]
|
||||
interface HandlerData
|
||||
{
|
||||
typedef struct _IA2Payload
|
||||
{
|
||||
IA2Data mData;
|
||||
IGeckoBackChannel* mGeckoBackChannel;
|
||||
} IA2Payload;
|
||||
}
|
||||
|
||||
[object,
|
||||
uuid(IHANDLERCONTROL_IID),
|
||||
async_uuid(ASYNCIHANDLERCONTROL_IID),
|
||||
pointer_default(unique)]
|
||||
interface IHandlerControl : IUnknown
|
||||
{
|
||||
HRESULT Invalidate();
|
||||
}
|
||||
|
||||
[object,
|
||||
uuid(IGECKOBACKCHANNEL_IID),
|
||||
pointer_default(unique)]
|
||||
interface IGeckoBackChannel : IUnknown
|
||||
{
|
||||
[propput] HRESULT HandlerControl([in] long aPid, [in] IHandlerControl* aCtrl);
|
||||
HRESULT Refresh([out] IA2Data* aOutData);
|
||||
}
|
||||
|
||||
[uuid(1e545f07-f108-4912-9471-546827a80983)]
|
||||
library AccessibleHandlerTypeLib
|
||||
{
|
||||
/**
|
||||
* This definition is required in order for the handler implementation to
|
||||
* support IDispatch (aka Automation). This is used by interpreted language
|
||||
* FFIs to discover which interfaces may be controlled via IDispatch.
|
||||
* (In particular, the python FFI used by NVDA needs this).
|
||||
*
|
||||
* In reality, the only a11y interface that is Automation compliant is
|
||||
* IAccessible; our remaining interfaces are not.
|
||||
*
|
||||
* Once the FFI knows that IAccessible is supported, the FFI queries for
|
||||
* IAccessible and is then able to resolve non-automation interfaces from
|
||||
* there.
|
||||
*/
|
||||
[uuid(HANDLER_CLSID)]
|
||||
coclass AccessibleHandler
|
||||
{
|
||||
[default] interface IAccessible;
|
||||
};
|
||||
};
|
38
accessible/ipc/win/handler/Makefile.in
Normal file
38
accessible/ipc/win/handler/Makefile.in
Normal file
@ -0,0 +1,38 @@
|
||||
# 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/.
|
||||
|
||||
IA2DIR = $(topsrcdir)/other-licenses/ia2
|
||||
MSAADIR = $(topsrcdir)/accessible/interfaces/msaa
|
||||
GARBAGE += $(MIDL_GENERATED_FILES) midl_done
|
||||
|
||||
MIDL_GENERATED_FILES = \
|
||||
dlldata.c \
|
||||
HandlerData.h \
|
||||
HandlerData_c.c \
|
||||
HandlerData_i.c \
|
||||
HandlerData_p.c \
|
||||
HandlerData.tlb \
|
||||
$(NULL)
|
||||
|
||||
export:: $(MIDL_GENERATED_FILES)
|
||||
|
||||
$(MIDL_GENERATED_FILES): midl_done
|
||||
|
||||
midl_done: HandlerData.acf HandlerData.idl
|
||||
$(MIDL) $(MIDL_FLAGS) -I $(IA2DIR) -I $(MSAADIR) -Oicf -acf $(srcdir)/HandlerData.acf $(srcdir)/HandlerData.idl
|
||||
touch $@
|
||||
|
||||
INSTALL_TARGETS += midl
|
||||
midl_FILES := HandlerData.h \
|
||||
HandlerData_i.c \
|
||||
$(NULL)
|
||||
midl_DEST := $(DIST)/include
|
||||
midl_TARGET := midl
|
||||
|
||||
export:: midl
|
||||
|
||||
register::
|
||||
regsvr32 -s $(DIST)/bin/$(SHARED_LIBRARY)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
60
accessible/ipc/win/handler/moz.build
Normal file
60
accessible/ipc/win/handler/moz.build
Normal file
@ -0,0 +1,60 @@
|
||||
# -*- Mode: python; 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/.
|
||||
|
||||
SharedLibrary('AccessibleHandler')
|
||||
|
||||
EXPORTS.mozilla.a11y += ['AccessibleHandler.h']
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/accessible/interfaces/ia2',
|
||||
'/ipc/mscom/oop',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'!dlldata.c',
|
||||
'!HandlerData_c.c',
|
||||
'!HandlerData_i.c',
|
||||
'!HandlerData_p.c',
|
||||
'AccessibleHandler.cpp',
|
||||
'AccessibleHandlerControl.cpp',
|
||||
]
|
||||
|
||||
GENERATED_FILES += [
|
||||
'dlldata.c',
|
||||
'HandlerData.h',
|
||||
'HandlerData.tlb',
|
||||
'HandlerData_c.c',
|
||||
'HandlerData_i.c',
|
||||
'HandlerData_p.c',
|
||||
]
|
||||
|
||||
DEFFILE = SRCDIR + '/AccessibleHandler.def'
|
||||
|
||||
USE_LIBS += [
|
||||
'mscom_oop',
|
||||
]
|
||||
|
||||
OS_LIBS += [
|
||||
'rpcrt4',
|
||||
]
|
||||
|
||||
RCINCLUDE = 'AccessibleHandler.rc'
|
||||
|
||||
# Since we are defining our own COM entry points (DllRegisterServer et al),
|
||||
# but we still want to be able to delegate some work to the generated code,
|
||||
# we add the prefix "Proxy" to all of the generated counterparts.
|
||||
DEFINES['ENTRY_PREFIX'] = 'Proxy'
|
||||
DEFINES['REGISTER_PROXY_DLL'] = True
|
||||
|
||||
# This DLL may be loaded into other processes, so we need static libs for
|
||||
# Windows 7 and Windows 8.
|
||||
USE_STATIC_LIBS = True
|
||||
|
||||
LIBRARY_DEFINES['UNICODE'] = True
|
||||
LIBRARY_DEFINES['_UNICODE'] = True
|
||||
LIBRARY_DEFINES['MOZ_NO_MOZALLOC'] = True
|
||||
DISABLE_STL_WRAPPING = True
|
||||
|
@ -5,7 +5,10 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
if CONFIG['COMPILE_ENVIRONMENT']:
|
||||
DIRS += ['typelib']
|
||||
DIRS += [
|
||||
'handler',
|
||||
'typelib',
|
||||
]
|
||||
|
||||
# With --disable-accessibility, we need to compile PDocAccessible.ipdl (which
|
||||
# also depends on COMPtrTypes.h), but not the C++.
|
||||
@ -15,13 +18,16 @@ EXPORTS.mozilla.a11y += ['COMPtrTypes.h']
|
||||
if CONFIG['ACCESSIBILITY']:
|
||||
EXPORTS.mozilla.a11y += [
|
||||
'DocAccessibleChild.h',
|
||||
'HandlerProvider.h',
|
||||
'PlatformChild.h',
|
||||
'ProxyAccessible.h'
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'!./handler/HandlerData_c.c',
|
||||
'COMPtrTypes.cpp',
|
||||
'DocAccessibleChild.cpp',
|
||||
'HandlerProvider.cpp',
|
||||
'PlatformChild.cpp',
|
||||
'ProxyAccessible.cpp',
|
||||
]
|
||||
|
@ -62,6 +62,7 @@ static gAccessibles = 0;
|
||||
#endif
|
||||
|
||||
MsaaIdGenerator AccessibleWrap::sIDGen;
|
||||
StaticAutoPtr<nsTArray<AccessibleWrap::HandlerControllerData>> AccessibleWrap::sHandlerControllers;
|
||||
|
||||
static const VARIANT kVarChildIdSelf = {VT_I4};
|
||||
|
||||
@ -1606,3 +1607,23 @@ AccessibleWrap::ReleaseContentProcessIdFor(dom::ContentParentId aIPCContentId)
|
||||
{
|
||||
sIDGen.ReleaseContentProcessIDFor(aIPCContentId);
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
AccessibleWrap::SetHandlerControl(DWORD aPid, RefPtr<IHandlerControl> aCtrl)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess() && NS_IsMainThread());
|
||||
|
||||
if (!sHandlerControllers) {
|
||||
sHandlerControllers = new nsTArray<HandlerControllerData>();
|
||||
ClearOnShutdown(&sHandlerControllers);
|
||||
}
|
||||
|
||||
HandlerControllerData ctrlData(aPid, Move(aCtrl));
|
||||
if (sHandlerControllers->Contains(ctrlData)) {
|
||||
return;
|
||||
}
|
||||
|
||||
sHandlerControllers->AppendElement(Move(ctrlData));
|
||||
}
|
||||
|
||||
|
@ -14,9 +14,11 @@
|
||||
#include "ia2AccessibleComponent.h"
|
||||
#include "ia2AccessibleHyperlink.h"
|
||||
#include "ia2AccessibleValue.h"
|
||||
#include "mozilla/a11y/AccessibleHandler.h"
|
||||
#include "mozilla/a11y/MsaaIdGenerator.h"
|
||||
#include "mozilla/a11y/ProxyAccessible.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/mscom/Utils.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
// Inheriting from both XPCOM and MSCOM interfaces causes a lot of warnings
|
||||
@ -188,6 +190,8 @@ public: // construction, destruction
|
||||
static uint32_t GetContentProcessIdFor(dom::ContentParentId aIPCContentId);
|
||||
static void ReleaseContentProcessIdFor(dom::ContentParentId aIPCContentId);
|
||||
|
||||
static void SetHandlerControl(DWORD aPid, RefPtr<IHandlerControl> aCtrl);
|
||||
|
||||
protected:
|
||||
virtual ~AccessibleWrap();
|
||||
|
||||
@ -242,6 +246,39 @@ protected:
|
||||
NAVRELATION_ERROR = 0x1017,
|
||||
NAVRELATION_ERROR_FOR = 0x1018
|
||||
};
|
||||
|
||||
struct HandlerControllerData final
|
||||
{
|
||||
HandlerControllerData(DWORD aPid, RefPtr<IHandlerControl>&& aCtrl)
|
||||
: mPid(aPid)
|
||||
, mCtrl(Move(aCtrl))
|
||||
{
|
||||
mIsProxy = mozilla::mscom::IsProxy(mCtrl);
|
||||
}
|
||||
|
||||
HandlerControllerData(HandlerControllerData&& aOther)
|
||||
: mPid(aOther.mPid)
|
||||
, mIsProxy(aOther.mIsProxy)
|
||||
, mCtrl(Move(aOther.mCtrl))
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(const HandlerControllerData& aOther) const
|
||||
{
|
||||
return mPid == aOther.mPid;
|
||||
}
|
||||
|
||||
bool operator==(const DWORD& aPid) const
|
||||
{
|
||||
return mPid == aPid;
|
||||
}
|
||||
|
||||
DWORD mPid;
|
||||
bool mIsProxy;
|
||||
RefPtr<IHandlerControl> mCtrl;
|
||||
};
|
||||
|
||||
static StaticAutoPtr<nsTArray<HandlerControllerData>> sHandlerControllers;
|
||||
};
|
||||
|
||||
static inline AccessibleWrap*
|
||||
|
@ -10,7 +10,7 @@ skip-if = (os == "linux" && debug) # linux: bug 976544
|
||||
[browser_devices_get_user_media_anim.js]
|
||||
[browser_devices_get_user_media_in_frame.js]
|
||||
[browser_devices_get_user_media_multi_process.js]
|
||||
skip-if = (e10s && debug) # bug 1347625
|
||||
skip-if = e10s && (asan || debug) # bug 1347625
|
||||
[browser_devices_get_user_media_screen.js]
|
||||
skip-if = (os == "linux") || (os == "win" && !debug) # bug 1320994 for linux opt, bug 1338038 for windows and linux debug
|
||||
[browser_devices_get_user_media_tear_off_tab.js]
|
||||
|
@ -44,6 +44,7 @@ module.exports = createClass({
|
||||
|
||||
let rotate = direction &&
|
||||
(direction == "left" || direction == "right") &&
|
||||
box !== "position" &&
|
||||
textContent.toString().length > LONG_TEXT_ROTATE_LIMIT;
|
||||
|
||||
return dom.p(
|
||||
|
@ -646,6 +646,14 @@ netmonitor.security.connection=Connection:
|
||||
# in the security tab describing the server certificate section.
|
||||
netmonitor.security.certificate=Certificate:
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.context.copy): This is the label displayed
|
||||
# for the copy sub-menu in the context menu for a request
|
||||
netmonitor.context.copy=Copy
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.context.copy.accesskey): This is the access key
|
||||
# for the copy sub-menu displayed in the context menu for a request
|
||||
netmonitor.context.copy.accesskey=C
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.context.copyUrl): This is the label displayed
|
||||
# on the context menu that copies the selected request's url
|
||||
netmonitor.context.copyUrl=Copy URL
|
||||
|
@ -50,7 +50,9 @@ RequestListContextMenu.prototype = {
|
||||
let selectedRequest = this.selectedRequest;
|
||||
|
||||
let menu = new Menu();
|
||||
menu.append(new MenuItem({
|
||||
let copySubmenu = new Menu();
|
||||
|
||||
copySubmenu.append(new MenuItem({
|
||||
id: "request-list-context-copy-url",
|
||||
label: L10N.getStr("netmonitor.context.copyUrl"),
|
||||
accesskey: L10N.getStr("netmonitor.context.copyUrl.accesskey"),
|
||||
@ -58,7 +60,7 @@ RequestListContextMenu.prototype = {
|
||||
click: () => this.copyUrl(),
|
||||
}));
|
||||
|
||||
menu.append(new MenuItem({
|
||||
copySubmenu.append(new MenuItem({
|
||||
id: "request-list-context-copy-url-params",
|
||||
label: L10N.getStr("netmonitor.context.copyUrlParams"),
|
||||
accesskey: L10N.getStr("netmonitor.context.copyUrlParams.accesskey"),
|
||||
@ -66,7 +68,7 @@ RequestListContextMenu.prototype = {
|
||||
click: () => this.copyUrlParams(),
|
||||
}));
|
||||
|
||||
menu.append(new MenuItem({
|
||||
copySubmenu.append(new MenuItem({
|
||||
id: "request-list-context-copy-post-data",
|
||||
label: L10N.getStr("netmonitor.context.copyPostData"),
|
||||
accesskey: L10N.getStr("netmonitor.context.copyPostData.accesskey"),
|
||||
@ -74,7 +76,7 @@ RequestListContextMenu.prototype = {
|
||||
click: () => this.copyPostData(),
|
||||
}));
|
||||
|
||||
menu.append(new MenuItem({
|
||||
copySubmenu.append(new MenuItem({
|
||||
id: "request-list-context-copy-as-curl",
|
||||
label: L10N.getStr("netmonitor.context.copyAsCurl"),
|
||||
accesskey: L10N.getStr("netmonitor.context.copyAsCurl.accesskey"),
|
||||
@ -82,12 +84,12 @@ RequestListContextMenu.prototype = {
|
||||
click: () => this.copyAsCurl(),
|
||||
}));
|
||||
|
||||
menu.append(new MenuItem({
|
||||
copySubmenu.append(new MenuItem({
|
||||
type: "separator",
|
||||
visible: !!selectedRequest,
|
||||
}));
|
||||
|
||||
menu.append(new MenuItem({
|
||||
copySubmenu.append(new MenuItem({
|
||||
id: "request-list-context-copy-request-headers",
|
||||
label: L10N.getStr("netmonitor.context.copyRequestHeaders"),
|
||||
accesskey: L10N.getStr("netmonitor.context.copyRequestHeaders.accesskey"),
|
||||
@ -95,7 +97,7 @@ RequestListContextMenu.prototype = {
|
||||
click: () => this.copyRequestHeaders(),
|
||||
}));
|
||||
|
||||
menu.append(new MenuItem({
|
||||
copySubmenu.append(new MenuItem({
|
||||
id: "response-list-context-copy-response-headers",
|
||||
label: L10N.getStr("netmonitor.context.copyResponseHeaders"),
|
||||
accesskey: L10N.getStr("netmonitor.context.copyResponseHeaders.accesskey"),
|
||||
@ -103,7 +105,7 @@ RequestListContextMenu.prototype = {
|
||||
click: () => this.copyResponseHeaders(),
|
||||
}));
|
||||
|
||||
menu.append(new MenuItem({
|
||||
copySubmenu.append(new MenuItem({
|
||||
id: "request-list-context-copy-response",
|
||||
label: L10N.getStr("netmonitor.context.copyResponse"),
|
||||
accesskey: L10N.getStr("netmonitor.context.copyResponse.accesskey"),
|
||||
@ -114,7 +116,7 @@ RequestListContextMenu.prototype = {
|
||||
click: () => this.copyResponse(),
|
||||
}));
|
||||
|
||||
menu.append(new MenuItem({
|
||||
copySubmenu.append(new MenuItem({
|
||||
id: "request-list-context-copy-image-as-data-uri",
|
||||
label: L10N.getStr("netmonitor.context.copyImageAsDataUri"),
|
||||
accesskey: L10N.getStr("netmonitor.context.copyImageAsDataUri.accesskey"),
|
||||
@ -124,12 +126,12 @@ RequestListContextMenu.prototype = {
|
||||
click: () => this.copyImageAsDataUri(),
|
||||
}));
|
||||
|
||||
menu.append(new MenuItem({
|
||||
copySubmenu.append(new MenuItem({
|
||||
type: "separator",
|
||||
visible: !!selectedRequest,
|
||||
}));
|
||||
|
||||
menu.append(new MenuItem({
|
||||
copySubmenu.append(new MenuItem({
|
||||
id: "request-list-context-copy-all-as-har",
|
||||
label: L10N.getStr("netmonitor.context.copyAllAsHar"),
|
||||
accesskey: L10N.getStr("netmonitor.context.copyAllAsHar.accesskey"),
|
||||
@ -137,6 +139,13 @@ RequestListContextMenu.prototype = {
|
||||
click: () => this.copyAllAsHar(),
|
||||
}));
|
||||
|
||||
menu.append(new MenuItem({
|
||||
label: L10N.getStr("netmonitor.context.copy"),
|
||||
accesskey: L10N.getStr("netmonitor.context.copy.accesskey"),
|
||||
visible: !!selectedRequest,
|
||||
submenu: copySubmenu,
|
||||
}));
|
||||
|
||||
menu.append(new MenuItem({
|
||||
id: "request-list-context-save-all-as-har",
|
||||
label: L10N.getStr("netmonitor.context.saveAllAsHar"),
|
||||
|
@ -41,6 +41,7 @@ add_task(function* () {
|
||||
data = yield createCurlData(requests.post, getLongString);
|
||||
testIsUrlEncodedRequest(data);
|
||||
testWritePostDataTextParams(data);
|
||||
testWriteEmptyPostDataTextParams(data);
|
||||
testDataArgumentOnGeneratedCommand(data);
|
||||
|
||||
data = yield createCurlData(requests.multipart, getLongString);
|
||||
@ -103,6 +104,12 @@ function testWritePostDataTextParams(data) {
|
||||
"Should return a serialized representation of the request parameters");
|
||||
}
|
||||
|
||||
function testWriteEmptyPostDataTextParams(data) {
|
||||
let params = CurlUtils.writePostDataTextParams(null);
|
||||
is(params, "",
|
||||
"Should return a empty string when no parameters provided");
|
||||
}
|
||||
|
||||
function testDataArgumentOnGeneratedCommand(data) {
|
||||
let curlCommand = Curl.generateCommand(data);
|
||||
ok(curlCommand.includes("--data"),
|
||||
|
@ -202,6 +202,9 @@ const CurlUtils = {
|
||||
* Post data parameters.
|
||||
*/
|
||||
writePostDataTextParams: function (postDataText) {
|
||||
if (!postDataText) {
|
||||
return "";
|
||||
}
|
||||
let lines = postDataText.split("\r\n");
|
||||
return lines[lines.length - 1];
|
||||
},
|
||||
|
@ -69,7 +69,7 @@ public:
|
||||
// we are in the middle of updating style. If we need to use this when
|
||||
// updating style, we should pass the nsStyleContext into this method and use
|
||||
// that to update the properties rather than calling
|
||||
// GetStyleContextForElement.
|
||||
// GetStyleContext.
|
||||
void SetTarget(const Nullable<ElementOrCSSPseudoElement>& aTarget);
|
||||
|
||||
void GetSpacing(nsString& aRetVal, CallerType aCallerType)
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
#include "Layers.h" // For Layer
|
||||
#include "nsComputedDOMStyle.h" // nsComputedDOMStyle::GetStyleContextForElement
|
||||
#include "nsComputedDOMStyle.h" // nsComputedDOMStyle::GetStyleContext
|
||||
#include "nsContentUtils.h" // nsContentUtils::ReportToConsole
|
||||
#include "nsCSSPropertyIDSet.h"
|
||||
#include "nsCSSProps.h" // For nsCSSProps::PropHasFlags
|
||||
@ -1061,9 +1061,7 @@ KeyframeEffectReadOnly::GetTargetStyleContext()
|
||||
? nsCSSPseudoElements::GetPseudoAtom(mTarget->mPseudoType)
|
||||
: nullptr;
|
||||
|
||||
return nsComputedDOMStyle::GetStyleContextForElement(mTarget->mElement,
|
||||
pseudo,
|
||||
shell);
|
||||
return nsComputedDOMStyle::GetStyleContext(mTarget->mElement, pseudo, shell);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -342,9 +342,9 @@ protected:
|
||||
|
||||
// Looks up the style context associated with the target element, if any.
|
||||
// We need to be careful to *not* call this when we are updating the style
|
||||
// context. That's because calling GetStyleContextForElement when we are in
|
||||
// the process of building a style context may trigger various forms of
|
||||
// infinite recursion.
|
||||
// context. That's because calling GetStyleContext when we are in the process
|
||||
// of building a style context may trigger various forms of infinite
|
||||
// recursion.
|
||||
already_AddRefed<nsStyleContext> GetTargetStyleContext();
|
||||
|
||||
// A wrapper for marking cascade update according to the current
|
||||
|
@ -93,6 +93,12 @@ public:
|
||||
mTabGroup->ValidateAccess();
|
||||
}
|
||||
|
||||
// Like ValidateAccess, but it returns a bool rather than asserting.
|
||||
bool AccessAllowed() const
|
||||
{
|
||||
return mTabGroup->AccessAllowed();
|
||||
}
|
||||
|
||||
// Return a pointer that can be continually checked to see if access to this
|
||||
// DocGroup is valid. This pointer should live at least as long as the
|
||||
// DocGroup.
|
||||
|
@ -458,7 +458,7 @@ Element::GetBindingURL(nsIDocument *aDocument, css::URLValue **aResult)
|
||||
|
||||
// Get the computed -moz-binding directly from the style context
|
||||
RefPtr<nsStyleContext> sc =
|
||||
nsComputedDOMStyle::GetStyleContextForElementNoFlush(this, nullptr, shell);
|
||||
nsComputedDOMStyle::GetStyleContextNoFlush(this, nullptr, shell);
|
||||
NS_ENSURE_TRUE(sc, false);
|
||||
|
||||
NS_IF_ADDREF(*aResult = sc->StyleDisplay()->mBinding);
|
||||
|
@ -310,6 +310,7 @@ StructuredCloneHolder::Read(nsISupports* aParent,
|
||||
mBlobImplArray.Clear();
|
||||
mWasmModuleArray.Clear();
|
||||
mClonedSurfaces.Clear();
|
||||
mInputStreamArray.Clear();
|
||||
Clear();
|
||||
}
|
||||
}
|
||||
@ -1042,6 +1043,45 @@ WriteWasmModule(JSStructuredCloneWriter* aWriter,
|
||||
return false;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
ReadInputStream(JSContext* aCx,
|
||||
uint32_t aIndex,
|
||||
StructuredCloneHolder* aHolder)
|
||||
{
|
||||
MOZ_ASSERT(aHolder);
|
||||
MOZ_ASSERT(aIndex < aHolder->InputStreams().Length());
|
||||
nsCOMPtr<nsIInputStream> inputStream = aHolder->InputStreams()[aIndex];
|
||||
|
||||
JS::RootedValue result(aCx);
|
||||
nsresult rv = nsContentUtils::WrapNative(aCx, inputStream,
|
||||
&NS_GET_IID(nsIInputStream),
|
||||
&result);
|
||||
if (NS_FAILED(rv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &result.toObject();
|
||||
}
|
||||
|
||||
bool
|
||||
WriteInputStream(JSStructuredCloneWriter* aWriter,
|
||||
nsIInputStream* aInputStream,
|
||||
StructuredCloneHolder* aHolder)
|
||||
{
|
||||
MOZ_ASSERT(aWriter);
|
||||
MOZ_ASSERT(aInputStream);
|
||||
MOZ_ASSERT(aHolder);
|
||||
|
||||
// We store the position of the inputStream in the array as index.
|
||||
if (JS_WriteUint32Pair(aWriter, SCTAG_DOM_INPUTSTREAM,
|
||||
aHolder->InputStreams().Length())) {
|
||||
aHolder->InputStreams().AppendElement(aInputStream);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
JSObject*
|
||||
@ -1084,6 +1124,10 @@ StructuredCloneHolder::CustomReadHandler(JSContext* aCx,
|
||||
return ReadWasmModule(aCx, aIndex, this);
|
||||
}
|
||||
|
||||
if (aTag == SCTAG_DOM_INPUTSTREAM) {
|
||||
return ReadInputStream(aCx, aIndex, this);
|
||||
}
|
||||
|
||||
return ReadFullySerializableObjects(aCx, aReader, aTag);
|
||||
}
|
||||
|
||||
@ -1149,6 +1193,14 @@ StructuredCloneHolder::CustomWriteHandler(JSContext* aCx,
|
||||
return WriteWasmModule(aWriter, module, this);
|
||||
}
|
||||
|
||||
{
|
||||
nsCOMPtr<nsISupports> base = xpc::UnwrapReflectorToISupports(aObj);
|
||||
nsCOMPtr<nsIInputStream> inputStream = do_QueryInterface(base);
|
||||
if (inputStream) {
|
||||
return WriteInputStream(aWriter, inputStream, this);
|
||||
}
|
||||
}
|
||||
|
||||
return WriteFullySerializableObjects(aCx, aWriter, aObj);
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,8 @@
|
||||
#include "nsIThread.h"
|
||||
#endif
|
||||
|
||||
class nsIInputStream;
|
||||
|
||||
namespace mozilla {
|
||||
class ErrorResult;
|
||||
namespace layers {
|
||||
@ -180,7 +182,8 @@ public:
|
||||
{
|
||||
return !mBlobImplArray.IsEmpty() ||
|
||||
!mWasmModuleArray.IsEmpty() ||
|
||||
!mClonedSurfaces.IsEmpty();
|
||||
!mClonedSurfaces.IsEmpty() ||
|
||||
!mInputStreamArray.IsEmpty();
|
||||
}
|
||||
|
||||
nsTArray<RefPtr<BlobImpl>>& BlobImpls()
|
||||
@ -195,6 +198,12 @@ public:
|
||||
return mWasmModuleArray;
|
||||
}
|
||||
|
||||
nsTArray<nsCOMPtr<nsIInputStream>>& InputStreams()
|
||||
{
|
||||
MOZ_ASSERT(mSupportsCloning, "InputStreams cannot be taken/set if cloning is not supported.");
|
||||
return mInputStreamArray;
|
||||
}
|
||||
|
||||
StructuredCloneScope CloneScope() const
|
||||
{
|
||||
return mStructuredCloneScope;
|
||||
@ -303,6 +312,9 @@ protected:
|
||||
// Used for cloning JS::WasmModules in the structured cloning algorithm.
|
||||
nsTArray<RefPtr<JS::WasmModule>> mWasmModuleArray;
|
||||
|
||||
// Used for cloning InputStream in the structured cloning algorithm.
|
||||
nsTArray<nsCOMPtr<nsIInputStream>> mInputStreamArray;
|
||||
|
||||
// This is used for sharing the backend of ImageBitmaps.
|
||||
// The DataSourceSurface object must be thread-safely reference-counted.
|
||||
// The DataSourceSurface object will not be written ever via any ImageBitmap
|
||||
|
@ -60,6 +60,8 @@ enum StructuredCloneTags {
|
||||
// This tag is used by both main thread and workers.
|
||||
SCTAG_DOM_URLSEARCHPARAMS,
|
||||
|
||||
SCTAG_DOM_INPUTSTREAM,
|
||||
|
||||
// When adding a new tag for IDB, please don't add it to the end of the list!
|
||||
// Tags that are supported by IDB must not ever change. See the static assert
|
||||
// in IDBObjectStore.cpp, method CommonStructuredCloneReadCallback.
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "mozilla/dom/WebKitCSSMatrixBinding.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsCSSParser.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsStyleTransformMatrix.h"
|
||||
#include "RuleNodeCacheConditions.h"
|
||||
|
||||
|
@ -537,7 +537,7 @@ nsContentSink::ProcessLinkHeader(const nsAString& aLinkData)
|
||||
while (ch != kNullCh && ch != kSemicolon && ch != kComma) {
|
||||
++end;
|
||||
|
||||
ch = *end;
|
||||
ch = *(end + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2444,7 +2444,7 @@ ComputeAnimationValue(nsCSSPropertyID aProperty,
|
||||
}
|
||||
|
||||
RefPtr<nsStyleContext> styleContext =
|
||||
nsComputedDOMStyle::GetStyleContextForElement(aElement, nullptr, shell);
|
||||
nsComputedDOMStyle::GetStyleContext(aElement, nullptr, shell);
|
||||
|
||||
if (!StyleAnimationValue::ComputeValue(aProperty, aElement, styleContext,
|
||||
aInput, false, aOutput)) {
|
||||
@ -2734,7 +2734,7 @@ nsDOMWindowUtils::ComputeAnimationDistance(nsIDOMElement* aElement,
|
||||
|
||||
nsIPresShell* shell = element->GetUncomposedDoc()->GetShell();
|
||||
RefPtr<nsStyleContext> styleContext = shell
|
||||
? nsComputedDOMStyle::GetStyleContextForElement(element, nullptr, shell)
|
||||
? nsComputedDOMStyle::GetStyleContext(element, nullptr, shell)
|
||||
: nullptr;
|
||||
if (!StyleAnimationValue::ComputeDistance(property, v1, v2, styleContext,
|
||||
*aResult)) {
|
||||
|
@ -1717,6 +1717,7 @@ nsMessageManagerScriptExecutor::InitChildGlobalInternal(
|
||||
// Set the location information for the new global, so that tools like
|
||||
// about:memory may use that information.
|
||||
xpc::SetLocationForGlobal(global, aID);
|
||||
xpc::SetDocGroupValidation(global);
|
||||
|
||||
DidCreateGlobal();
|
||||
return true;
|
||||
|
@ -1816,8 +1816,7 @@ bool
|
||||
nsPlainTextSerializer::IsElementPreformatted(Element* aElement)
|
||||
{
|
||||
RefPtr<nsStyleContext> styleContext =
|
||||
nsComputedDOMStyle::GetStyleContextForElementNoFlush(aElement, nullptr,
|
||||
nullptr);
|
||||
nsComputedDOMStyle::GetStyleContextNoFlush(aElement, nullptr, nullptr);
|
||||
if (styleContext) {
|
||||
const nsStyleText* textStyle = styleContext->StyleText();
|
||||
return textStyle->WhiteSpaceOrNewlineIsSignificant();
|
||||
@ -1830,8 +1829,7 @@ bool
|
||||
nsPlainTextSerializer::IsElementBlock(Element* aElement)
|
||||
{
|
||||
RefPtr<nsStyleContext> styleContext =
|
||||
nsComputedDOMStyle::GetStyleContextForElementNoFlush(aElement, nullptr,
|
||||
nullptr);
|
||||
nsComputedDOMStyle::GetStyleContextNoFlush(aElement, nullptr, nullptr);
|
||||
if (styleContext) {
|
||||
const nsStyleDisplay* displayStyle = styleContext->StyleDisplay();
|
||||
return displayStyle->IsBlockOutsideStyle();
|
||||
|
@ -3467,8 +3467,7 @@ ElementIsVisibleNoFlush(Element* aElement)
|
||||
return false;
|
||||
}
|
||||
RefPtr<nsStyleContext> sc =
|
||||
nsComputedDOMStyle::GetStyleContextForElementNoFlush(aElement, nullptr,
|
||||
nullptr);
|
||||
nsComputedDOMStyle::GetStyleContextNoFlush(aElement, nullptr, nullptr);
|
||||
return sc && sc->StyleVisibility()->IsVisible();
|
||||
}
|
||||
|
||||
|
@ -817,8 +817,8 @@ nsXHTMLContentSerializer::IsElementPreformatted(nsIContent* aNode)
|
||||
return false;
|
||||
}
|
||||
RefPtr<nsStyleContext> styleContext =
|
||||
nsComputedDOMStyle::GetStyleContextForElementNoFlush(aNode->AsElement(),
|
||||
nullptr, nullptr);
|
||||
nsComputedDOMStyle::GetStyleContextNoFlush(aNode->AsElement(),
|
||||
nullptr, nullptr);
|
||||
if (styleContext) {
|
||||
const nsStyleText* textStyle = styleContext->StyleText();
|
||||
return textStyle->WhiteSpaceOrNewlineIsSignificant();
|
||||
|
@ -9,6 +9,7 @@ support-files =
|
||||
file_bug1303838.html
|
||||
file_bug1303838_target.html
|
||||
file_bug1303838_with_iframe.html
|
||||
file_docgroup_forbid.html
|
||||
file_messagemanager_unload.html
|
||||
file_pluginAudio.html
|
||||
file_use_counter_outer.html
|
||||
@ -26,6 +27,8 @@ support-files =
|
||||
tags = mcb
|
||||
[browser_bug1011748.js]
|
||||
[browser_bug1058164.js]
|
||||
[browser_docgroup_forbid.js]
|
||||
skip-if = !e10s
|
||||
[browser_messagemanager_loadprocessscript.js]
|
||||
[browser_messagemanager_targetframeloader.js]
|
||||
[browser_messagemanager_unload.js]
|
||||
@ -37,3 +40,4 @@ skip-if = true # Bug 1271028
|
||||
[browser_bug1307747.js]
|
||||
[browser_timeout_throttling_with_audio_playback.js]
|
||||
[browser_bug1303838.js]
|
||||
[browser_inputStream_structuredClone.js]
|
||||
|
74
dom/base/test/browser_docgroup_forbid.js
Normal file
74
dom/base/test/browser_docgroup_forbid.js
Normal file
@ -0,0 +1,74 @@
|
||||
const url = "https://example.com/browser/dom/base/test/file_docgroup_forbid.html";
|
||||
|
||||
function frameScript() {
|
||||
let e = Services.ww.getWindowEnumerator();
|
||||
let exception = false;
|
||||
while (e.hasMoreElements()) {
|
||||
try {
|
||||
/*
|
||||
* If this is a window we're not supposed to touch, we'll get an
|
||||
* error very early here (during the QI).
|
||||
*/
|
||||
var window = e.getNext().QueryInterface(Components.interfaces.nsIDOMWindow);
|
||||
var doc = window.document;
|
||||
} catch (e) {
|
||||
if (/accessing object in wrong DocGroup/.test(e.toString())) {
|
||||
exception = true;
|
||||
break;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do some stuff that will trigger the DocGroup assertions if we
|
||||
* didn't throw.
|
||||
*/
|
||||
|
||||
let elt = doc.createElement("div");
|
||||
elt.innerHTML = "hello!";
|
||||
doc.body.appendChild(elt);
|
||||
|
||||
let evt = new window.CustomEvent("foopy");
|
||||
doc.dispatchEvent(evt);
|
||||
}
|
||||
sendAsyncMessage("DocGroupTest:Done", exception);
|
||||
}
|
||||
|
||||
function promiseMessage(messageManager, message) {
|
||||
return new Promise(resolve => {
|
||||
let listener = (msg) => {
|
||||
messageManager.removeMessageListener(message, listener);
|
||||
resolve(msg);
|
||||
};
|
||||
|
||||
messageManager.addMessageListener(message, listener);
|
||||
})
|
||||
}
|
||||
|
||||
add_task(function*() {
|
||||
// This pref is normally disabled during tests, but we want to test
|
||||
// it here, so we enable it.
|
||||
yield new Promise(go => {
|
||||
SpecialPowers.pushPrefEnv({set: [["extensions.throw_on_docgroup_mismatch.enabled", true]]}, go)
|
||||
});
|
||||
|
||||
let url1 = url + "?tab=1";
|
||||
let url2 = url + "?tab=2";
|
||||
|
||||
let browser1 = gBrowser.selectedBrowser;
|
||||
|
||||
let tab2 = gBrowser.addTab(url2, {sameProcessAsFrameLoader: browser1.frameLoader});
|
||||
let browser2 = tab2.linkedBrowser;
|
||||
yield BrowserTestUtils.browserLoaded(browser2, false, url2);
|
||||
|
||||
browser1.loadURI(url1);
|
||||
yield BrowserTestUtils.browserLoaded(browser1, false, url1);
|
||||
|
||||
browser1.messageManager.loadFrameScript(`data:,(${frameScript})();`, false);
|
||||
|
||||
let exception = yield promiseMessage(browser1.messageManager, "DocGroupTest:Done");
|
||||
|
||||
ok(exception, "Touching two windows threw an exception (that's good!)");
|
||||
|
||||
gBrowser.removeTab(tab2);
|
||||
});
|
56
dom/base/test/browser_inputStream_structuredClone.js
Normal file
56
dom/base/test/browser_inputStream_structuredClone.js
Normal file
@ -0,0 +1,56 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const { classes: Cc, interfaces: Ci } = Components;
|
||||
const URIs = [
|
||||
"about:about",
|
||||
"http://example.com/browser/dom/base/test/empty.html"
|
||||
];
|
||||
|
||||
function* runTest(input, url) {
|
||||
let tab = gBrowser.addTab(url);
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
|
||||
yield BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
let stream = Cc['@mozilla.org/io/string-input-stream;1']
|
||||
.createInstance(Ci.nsIStringInputStream);
|
||||
stream.setData(input, input.length);
|
||||
|
||||
let data = {
|
||||
inputStream: stream
|
||||
};
|
||||
|
||||
is(data.inputStream.available(), input.length, "The length of the inputStream matches: " + input.length);
|
||||
|
||||
let dataBack = yield ContentTask.spawn(browser, data, function(data) {
|
||||
let dataBack = {
|
||||
inputStream: data.inputStream,
|
||||
check: true,
|
||||
};
|
||||
|
||||
if (content.location.href.startsWith('about:')) {
|
||||
dataBack.check = data.inputStream instanceof content.Components.interfaces.nsIInputStream;
|
||||
}
|
||||
|
||||
return dataBack;
|
||||
});
|
||||
|
||||
ok(dataBack.check, "The inputStream is a nsIInputStream also on content.");
|
||||
ok(data.inputStream instanceof Ci.nsIInputStream, "The original object was an inputStream");
|
||||
ok(dataBack.inputStream instanceof Ci.nsIInputStream, "We have an inputStream back from the content.");
|
||||
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
}
|
||||
|
||||
add_task(function* test() {
|
||||
let a = "a";
|
||||
for (let i = 0; i < 25; ++i) {
|
||||
a+=a;
|
||||
}
|
||||
|
||||
for (let i = 0; i < URIs.length; ++i) {
|
||||
yield runTest("Hello world", URIs[i]);
|
||||
yield runTest(a, URIs[i]);
|
||||
}
|
||||
});
|
7
dom/base/test/file_docgroup_forbid.html
Normal file
7
dom/base/test/file_docgroup_forbid.html
Normal file
@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
<script>
|
||||
document.addEventListener("foopy", function() { dump("ran event handler\n"); });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -653,7 +653,7 @@ skip-if = (toolkit == 'android') # Android: Bug 775227
|
||||
[test_innersize_scrollport.html]
|
||||
[test_integer_attr_with_leading_zero.html]
|
||||
[test_intersectionobservers.html]
|
||||
skip-if = true # Track Bug 1320704
|
||||
skip-if = (os == "android") # Timing issues
|
||||
[test_link_prefetch.html]
|
||||
skip-if = !e10s # Track Bug 1281415
|
||||
[test_link_stylesheet.html]
|
||||
|
@ -1555,10 +1555,8 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
|
||||
def hasMembersInSlots(self):
|
||||
return self._ownMembersInSlots != 0
|
||||
|
||||
conditionExtendedAttributes = [ "Pref", "ChromeOnly", "Func", "AvailableIn",
|
||||
"SecureContext",
|
||||
"CheckAnyPermissions",
|
||||
"CheckAllPermissions" ]
|
||||
conditionExtendedAttributes = [ "Pref", "ChromeOnly", "Func",
|
||||
"SecureContext" ]
|
||||
def isExposedConditionally(self, exclusions=[]):
|
||||
return any(((not a in exclusions) and self.getExtendedAttribute(a)) for a in self.conditionExtendedAttributes)
|
||||
|
||||
|
@ -4,6 +4,9 @@
|
||||
|
||||
include protocol PBackground;
|
||||
include protocol PBlob;
|
||||
include protocol PChildToParentStream;
|
||||
include protocol PFileDescriptorSet;
|
||||
include protocol PParentToChildStream;
|
||||
include DOMTypes;
|
||||
|
||||
using struct mozilla::SerializedStructuredCloneBuffer from "ipc/IPCMessageUtils.h";
|
||||
|
@ -1146,8 +1146,9 @@ CanvasRenderingContext2D::ParseColor(const nsAString& aString,
|
||||
RefPtr<nsStyleContext> parentContext;
|
||||
if (mCanvasElement && mCanvasElement->IsInUncomposedDoc()) {
|
||||
// Inherit from the canvas element.
|
||||
parentContext = nsComputedDOMStyle::GetStyleContextForElement(
|
||||
mCanvasElement, nullptr, presShell);
|
||||
parentContext = nsComputedDOMStyle::GetStyleContext(mCanvasElement,
|
||||
nullptr,
|
||||
presShell);
|
||||
}
|
||||
|
||||
Unused << nsRuleNode::ComputeColor(
|
||||
@ -1939,9 +1940,7 @@ CanvasRenderingContext2D::ClearTarget()
|
||||
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
|
||||
if (presShell) {
|
||||
canvasStyle =
|
||||
nsComputedDOMStyle::GetStyleContextForElement(mCanvasElement,
|
||||
nullptr,
|
||||
presShell);
|
||||
nsComputedDOMStyle::GetStyleContext(mCanvasElement, nullptr, presShell);
|
||||
if (canvasStyle) {
|
||||
WritingMode wm(canvasStyle);
|
||||
if (wm.IsVertical() && !wm.IsSideways()) {
|
||||
@ -2649,8 +2648,7 @@ GetFontParentStyleContext(Element* aElement, nsIPresShell* aPresShell,
|
||||
if (aElement && aElement->IsInUncomposedDoc()) {
|
||||
// Inherit from the canvas element.
|
||||
RefPtr<nsStyleContext> result =
|
||||
nsComputedDOMStyle::GetStyleContextForElement(aElement, nullptr,
|
||||
aPresShell);
|
||||
nsComputedDOMStyle::GetStyleContext(aElement, nullptr, aPresShell);
|
||||
if (!result) {
|
||||
aError.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
@ -4202,9 +4200,7 @@ CanvasRenderingContext2D::DrawOrMeasureText(const nsAString& aRawText,
|
||||
if (mCanvasElement && mCanvasElement->IsInUncomposedDoc()) {
|
||||
// try to find the closest context
|
||||
canvasStyle =
|
||||
nsComputedDOMStyle::GetStyleContextForElement(mCanvasElement,
|
||||
nullptr,
|
||||
presShell);
|
||||
nsComputedDOMStyle::GetStyleContext(mCanvasElement, nullptr, presShell);
|
||||
if (!canvasStyle) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -2950,8 +2950,8 @@ IsOrHasAncestorWithDisplayNone(Element* aElement, nsIPresShell* aPresShell)
|
||||
if (sc) {
|
||||
sc = styleSet->ResolveStyleFor(elementsToCheck[i], sc, LazyComputeBehavior::Assert);
|
||||
} else {
|
||||
sc = nsComputedDOMStyle::GetStyleContextForElementNoFlush(elementsToCheck[i],
|
||||
nullptr, aPresShell);
|
||||
sc = nsComputedDOMStyle::GetStyleContextNoFlush(elementsToCheck[i],
|
||||
nullptr, aPresShell);
|
||||
}
|
||||
if (sc->StyleDisplay()->mDisplay == StyleDisplay::None) {
|
||||
return true;
|
||||
|
@ -172,6 +172,9 @@
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
#include "nsAccessibilityService.h"
|
||||
#ifdef XP_WIN
|
||||
#include "mozilla/a11y/AccessibleWrap.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "mozilla/dom/File.h"
|
||||
|
@ -4925,6 +4925,20 @@ ContentParent::RecvGetA11yContentId(uint32_t* aContentId)
|
||||
#endif
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentParent::RecvA11yHandlerControl(const uint32_t& aPid,
|
||||
const IHandlerControlHolder& aHandlerControl)
|
||||
{
|
||||
#if defined(XP_WIN32) && defined(ACCESSIBILITY)
|
||||
MOZ_ASSERT(!aHandlerControl.IsNull());
|
||||
RefPtr<IHandlerControl> proxy(aHandlerControl.Get());
|
||||
a11y::AccessibleWrap::SetHandlerControl(aPid, Move(proxy));
|
||||
return IPC_OK();
|
||||
#else
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -599,6 +599,10 @@ public:
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvGetA11yContentId(uint32_t* aContentId) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvA11yHandlerControl(const uint32_t& aPid,
|
||||
const IHandlerControlHolder& aHandlerControl) override;
|
||||
|
||||
virtual int32_t Pid() const override;
|
||||
|
||||
virtual PURLClassifierParent*
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
include protocol PBlob;
|
||||
include protocol PMemoryStream;
|
||||
|
||||
include IPCStream;
|
||||
include ProtocolTypes;
|
||||
|
||||
using struct mozilla::void_t
|
||||
@ -40,6 +42,7 @@ struct ClonedMessageData
|
||||
{
|
||||
SerializedStructuredCloneBuffer data;
|
||||
PBlob[] blobs;
|
||||
IPCStream[] inputStreams;
|
||||
MessagePortIdentifier[] identfiers;
|
||||
};
|
||||
|
||||
|
@ -16,6 +16,9 @@ include protocol PIndexedDBPermissionRequest;
|
||||
include protocol PRenderFrame;
|
||||
include protocol PPluginWidget;
|
||||
include protocol PRemotePrintJob;
|
||||
include protocol PChildToParentStream;
|
||||
include protocol PParentToChildStream;
|
||||
include protocol PFileDescriptorSet;
|
||||
include DOMTypes;
|
||||
include JavaScriptTypes;
|
||||
include URIParams;
|
||||
|
@ -73,6 +73,7 @@ using base::ProcessId from "base/process.h";
|
||||
using struct IPC::Permission from "mozilla/net/NeckoMessageUtils.h";
|
||||
using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
|
||||
using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
|
||||
using mozilla::a11y::IHandlerControlHolder from "mozilla/a11y/IPCTypes.h";
|
||||
using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
|
||||
using mozilla::hal::ProcessPriority from "mozilla/HalTypes.h";
|
||||
using mozilla::gfx::IntSize from "mozilla/gfx/2D.h";
|
||||
@ -1083,6 +1084,8 @@ parent:
|
||||
async RecordChildEvents(ChildEventData[] events);
|
||||
|
||||
sync GetA11yContentId() returns (uint32_t aContentId);
|
||||
async A11yHandlerControl(uint32_t aPid,
|
||||
IHandlerControlHolder aHandlerControl);
|
||||
|
||||
async AddMemoryReport(MemoryReport aReport);
|
||||
async FinishMemoryReport(uint32_t aGeneration);
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/BlobBinding.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
#include "mozilla/ipc/IPCStreamUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsJSEnvironment.h"
|
||||
#include "MainThreadUtils.h"
|
||||
@ -25,6 +25,37 @@ namespace mozilla {
|
||||
namespace dom {
|
||||
namespace ipc {
|
||||
|
||||
StructuredCloneData::StructuredCloneData()
|
||||
: StructuredCloneData(StructuredCloneHolder::TransferringSupported)
|
||||
{}
|
||||
|
||||
StructuredCloneData::StructuredCloneData(StructuredCloneData&& aOther)
|
||||
: StructuredCloneData(StructuredCloneHolder::TransferringSupported)
|
||||
{
|
||||
*this = Move(aOther);
|
||||
}
|
||||
|
||||
StructuredCloneData::StructuredCloneData(TransferringSupport aSupportsTransferring)
|
||||
: StructuredCloneHolder(StructuredCloneHolder::CloningSupported,
|
||||
aSupportsTransferring,
|
||||
StructuredCloneHolder::StructuredCloneScope::DifferentProcess)
|
||||
, mInitialized(false)
|
||||
{}
|
||||
|
||||
StructuredCloneData::~StructuredCloneData()
|
||||
{}
|
||||
|
||||
StructuredCloneData&
|
||||
StructuredCloneData::operator=(StructuredCloneData&& aOther)
|
||||
{
|
||||
mExternalData = Move(aOther.mExternalData);
|
||||
mSharedData = Move(aOther.mSharedData);
|
||||
mIPCStreams = Move(aOther.mIPCStreams);
|
||||
mInitialized = aOther.mInitialized;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
StructuredCloneData::Copy(const StructuredCloneData& aData)
|
||||
{
|
||||
@ -50,6 +81,9 @@ StructuredCloneData::Copy(const StructuredCloneData& aData)
|
||||
MOZ_ASSERT(GetSurfaces().IsEmpty());
|
||||
MOZ_ASSERT(WasmModules().IsEmpty());
|
||||
|
||||
MOZ_ASSERT(InputStreams().IsEmpty());
|
||||
InputStreams().AppendElements(aData.InputStreams());
|
||||
|
||||
mInitialized = true;
|
||||
|
||||
return true;
|
||||
@ -224,6 +258,26 @@ BuildClonedMessageData(typename ParentManagerTraits<Flavor, ManagerFlavor>::Conc
|
||||
blobList.AppendElement(protocolActor);
|
||||
}
|
||||
}
|
||||
|
||||
const nsTArray<nsCOMPtr<nsIInputStream>>& inputStreams = aData.InputStreams();
|
||||
|
||||
if (!inputStreams.IsEmpty()) {
|
||||
InfallibleTArray<IPCStream>& streams = aClonedData.inputStreams();
|
||||
uint32_t length = inputStreams.Length();
|
||||
streams.SetCapacity(length);
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
AutoIPCStream* stream = aData.IPCStreams().AppendElement(fallible);
|
||||
if (NS_WARN_IF(!stream)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!stream->Serialize(inputStreams[i], aManager)) {
|
||||
return false;
|
||||
}
|
||||
streams.AppendElement(stream->TakeValue());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -343,6 +397,16 @@ UnpackClonedMessageData(typename MemoryTraits<MemoryFlavor>::ClonedMessageType&
|
||||
aData.BlobImpls().AppendElement(blobImpl);
|
||||
}
|
||||
}
|
||||
|
||||
const InfallibleTArray<IPCStream>& streams = aClonedData.inputStreams();
|
||||
if (!streams.IsEmpty()) {
|
||||
uint32_t length = streams.Length();
|
||||
aData.InputStreams().SetCapacity(length);
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(streams[i]);
|
||||
aData.InputStreams().AppendElement(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/dom/StructuredCloneHolder.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsIInputStream.h"
|
||||
|
||||
namespace IPC {
|
||||
class Message;
|
||||
@ -20,6 +21,7 @@ class PickleIterator;
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
class AutoIPCStream;
|
||||
class PBackgroundChild;
|
||||
class PBackgroundParent;
|
||||
|
||||
@ -150,22 +152,19 @@ private:
|
||||
class StructuredCloneData : public StructuredCloneHolder
|
||||
{
|
||||
public:
|
||||
StructuredCloneData()
|
||||
: StructuredCloneData(StructuredCloneHolder::TransferringSupported)
|
||||
{}
|
||||
StructuredCloneData();
|
||||
|
||||
StructuredCloneData(const StructuredCloneData&) = delete;
|
||||
|
||||
StructuredCloneData(StructuredCloneData&& aOther) = default;
|
||||
StructuredCloneData(StructuredCloneData&& aOther);
|
||||
|
||||
~StructuredCloneData()
|
||||
{}
|
||||
~StructuredCloneData();
|
||||
|
||||
StructuredCloneData&
|
||||
operator=(const StructuredCloneData& aOther) = delete;
|
||||
|
||||
StructuredCloneData&
|
||||
operator=(StructuredCloneData&& aOther) = default;
|
||||
operator=(StructuredCloneData&& aOther);
|
||||
|
||||
const nsTArray<RefPtr<BlobImpl>>& BlobImpls() const
|
||||
{
|
||||
@ -177,6 +176,16 @@ public:
|
||||
return mBlobImplArray;
|
||||
}
|
||||
|
||||
const nsTArray<nsCOMPtr<nsIInputStream>>& InputStreams() const
|
||||
{
|
||||
return mInputStreamArray;
|
||||
}
|
||||
|
||||
nsTArray<nsCOMPtr<nsIInputStream>>& InputStreams()
|
||||
{
|
||||
return mInputStreamArray;
|
||||
}
|
||||
|
||||
bool Copy(const StructuredCloneData& aData);
|
||||
|
||||
void Read(JSContext* aCx,
|
||||
@ -276,29 +285,33 @@ public:
|
||||
return mSupportsTransferring;
|
||||
}
|
||||
|
||||
FallibleTArray<mozilla::ipc::AutoIPCStream>& IPCStreams()
|
||||
{
|
||||
return mIPCStreams;
|
||||
}
|
||||
|
||||
// For IPC serialization
|
||||
void WriteIPCParams(IPC::Message* aMessage) const;
|
||||
bool ReadIPCParams(const IPC::Message* aMessage, PickleIterator* aIter);
|
||||
|
||||
protected:
|
||||
explicit StructuredCloneData(TransferringSupport aSupportsTransferring)
|
||||
: StructuredCloneHolder(StructuredCloneHolder::CloningSupported,
|
||||
aSupportsTransferring,
|
||||
StructuredCloneHolder::StructuredCloneScope::DifferentProcess)
|
||||
, mInitialized(false)
|
||||
{}
|
||||
|
||||
explicit StructuredCloneData(TransferringSupport aSupportsTransferring);
|
||||
|
||||
private:
|
||||
JSStructuredCloneData mExternalData;
|
||||
RefPtr<SharedJSAllocatedData> mSharedData;
|
||||
|
||||
// This array is needed because AutoIPCStream DTOR must be executed after the
|
||||
// sending of the data via IPC. This will be fixed by bug 1353475.
|
||||
FallibleTArray<mozilla::ipc::AutoIPCStream> mIPCStreams;
|
||||
bool mInitialized;
|
||||
};
|
||||
|
||||
/**
|
||||
* For use when transferring should not be supported.
|
||||
*/
|
||||
class StructuredCloneDataNoTransfers : public StructuredCloneData {
|
||||
class StructuredCloneDataNoTransfers : public StructuredCloneData
|
||||
{
|
||||
public:
|
||||
StructuredCloneDataNoTransfers()
|
||||
: StructuredCloneData(StructuredCloneHolder::TransferringNotSupported)
|
||||
|
@ -0,0 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="reftest-wait">
|
||||
<script>
|
||||
const blockSize = 128;
|
||||
// The sample rate is a prime number so that the resampler is not expected to
|
||||
// simplify in/out fractions.
|
||||
const rate = 44101;
|
||||
var context = new window.OfflineAudioContext(1, 3 * blockSize, rate);
|
||||
// Non-zero buffer, so it can't be optimized away.
|
||||
var buffer = context.createBuffer(1, 128, rate);
|
||||
buffer.getChannelData(0)[0] = 1.0;
|
||||
var source = context.createBufferSource();
|
||||
source.buffer = buffer;
|
||||
source.loop = true;
|
||||
// Initialize the resampler with a slow input rate.
|
||||
// With the current (Mar 2017) implementation, very slow rates give the
|
||||
// resampler a very large denominator.
|
||||
source.playbackRate.setValueAtTime(rate / 0x7fffffff, 0.0);
|
||||
// Change to a moderate input rate.
|
||||
// With the current implementation, skip_frac_num increases by den_rate for
|
||||
// each output sample and so one block before the change in playback rate is
|
||||
// enough for high skip_frac_num at the time of the change.
|
||||
const changeBlock = 1;
|
||||
const changeBlockSeconds = changeBlock * blockSize / rate;
|
||||
// With the current speex_resampler_set_rate_frac() implementation, the
|
||||
// moderate resampler denominator is still large enough to trigger overflow of
|
||||
// 32-bit unsigned integer arithmetic.
|
||||
source.playbackRate.setValueAtTime(rate / (rate + 1), changeBlockSeconds);
|
||||
source.start(0);
|
||||
context.startRendering().
|
||||
then(function() {
|
||||
document.documentElement.removeAttribute("class");
|
||||
});
|
||||
</script>
|
@ -92,6 +92,7 @@ load audiocontext-double-suspend.html
|
||||
load buffer-source-duration-1.html
|
||||
load buffer-source-ended-1.html
|
||||
load buffer-source-resampling-start-1.html
|
||||
load buffer-source-slow-resampling-1.html
|
||||
load doppler-1.html
|
||||
HTTP load media-element-source-seek-1.html
|
||||
load offline-buffer-source-ended-1.html
|
||||
|
@ -190,13 +190,15 @@ namespace WebAudioUtils {
|
||||
MOZ_CRASH("We should never see a NaN here");
|
||||
}
|
||||
|
||||
if (f > FloatType(numeric_limits<IntType>::max())) {
|
||||
// If the floating point value is outside of the range of maximum
|
||||
// integral value for this type, just clamp to the maximum value.
|
||||
// If the floating point value is outside of the range of maximum
|
||||
// integral value for this type, just clamp to the maximum value.
|
||||
// The equality case must also return max() due to loss of precision when
|
||||
// converting max() to float.
|
||||
if (f >= FloatType(numeric_limits<IntType>::max())) {
|
||||
return numeric_limits<IntType>::max();
|
||||
}
|
||||
|
||||
if (f < FloatType(numeric_limits<IntType>::min())) {
|
||||
if (f <= FloatType(numeric_limits<IntType>::min())) {
|
||||
// If the floating point value is outside of the range of minimum
|
||||
// integral value for this type, just clamp to the minimum value.
|
||||
return numeric_limits<IntType>::min();
|
||||
|
@ -3,6 +3,9 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include protocol PBackground;
|
||||
include protocol PChildToParentStream;
|
||||
include protocol PFileDescriptorSet;
|
||||
include protocol PParentToChildStream;
|
||||
include protocol PBlob;
|
||||
|
||||
include DOMTypes;
|
||||
|
@ -203,7 +203,8 @@ public:
|
||||
NotificationGetRunnable(const nsAString& aOrigin,
|
||||
const nsAString& aTag,
|
||||
nsINotificationStorageCallback* aCallback)
|
||||
: mOrigin(aOrigin), mTag(aTag), mCallback(aCallback)
|
||||
: Runnable("NotificationGetRunnable")
|
||||
, mOrigin(aOrigin), mTag(aTag), mCallback(aCallback)
|
||||
{}
|
||||
|
||||
NS_IMETHOD
|
||||
@ -310,7 +311,8 @@ class FocusWindowRunnable final : public Runnable
|
||||
nsMainThreadPtrHandle<nsPIDOMWindowInner> mWindow;
|
||||
public:
|
||||
explicit FocusWindowRunnable(const nsMainThreadPtrHandle<nsPIDOMWindowInner>& aWindow)
|
||||
: mWindow(aWindow)
|
||||
: Runnable("FocusWindowRunnable")
|
||||
, mWindow(aWindow)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD
|
||||
@ -502,8 +504,10 @@ public:
|
||||
eClose
|
||||
};
|
||||
|
||||
NotificationTask(UniquePtr<NotificationRef> aRef, NotificationAction aAction)
|
||||
: mNotificationRef(Move(aRef)), mAction(aAction)
|
||||
NotificationTask(const char* aName, UniquePtr<NotificationRef> aRef,
|
||||
NotificationAction aAction)
|
||||
: Runnable(aName)
|
||||
, mNotificationRef(Move(aRef)), mAction(aAction)
|
||||
{}
|
||||
|
||||
NS_IMETHOD
|
||||
@ -619,8 +623,13 @@ NotificationPermissionRequest::GetRequester(nsIContentPermissionRequester** aReq
|
||||
inline nsresult
|
||||
NotificationPermissionRequest::DispatchResolvePromise()
|
||||
{
|
||||
return NS_DispatchToMainThread(NewRunnableMethod(this,
|
||||
&NotificationPermissionRequest::ResolvePromise));
|
||||
nsCOMPtr<nsIRunnable> resolver =
|
||||
NewRunnableMethod("NotificationPermissionRequest::DispatchResolvePromise",
|
||||
this, &NotificationPermissionRequest::ResolvePromise);
|
||||
if (nsIEventTarget* target = mWindow->EventTargetFor(TaskCategory::Other)) {
|
||||
return target->Dispatch(resolver.forget(), nsIEventTarget::DISPATCH_NORMAL);
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -1399,7 +1408,7 @@ public:
|
||||
MOZ_ASSERT_IF(mWorkerPrivate->IsServiceWorker(), !doDefaultAction);
|
||||
if (doDefaultAction) {
|
||||
RefPtr<FocusWindowRunnable> r = new FocusWindowRunnable(mWindow);
|
||||
NS_DispatchToMainThread(r);
|
||||
mWorkerPrivate->DispatchToMainThread(r.forget());
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -1831,11 +1840,14 @@ Notification::RequestPermissionEnabledForScope(JSContext* aCx, JSObject* /* unus
|
||||
return NS_IsMainThread();
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<Promise>
|
||||
Notification::RequestPermission(const GlobalObject& aGlobal,
|
||||
const Optional<OwningNonNull<NotificationPermissionCallback> >& aCallback,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
// Get principal from global to make permission request for notifications.
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
@ -1857,7 +1869,9 @@ Notification::RequestPermission(const GlobalObject& aGlobal,
|
||||
nsCOMPtr<nsIRunnable> request =
|
||||
new NotificationPermissionRequest(principal, window, promise, permissionCallback);
|
||||
|
||||
NS_DispatchToMainThread(request);
|
||||
global->Dispatch("Notification::RequestPermission", TaskCategory::Other,
|
||||
request.forget());
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
@ -2026,6 +2040,7 @@ Notification::Get(nsPIDOMWindowInner* aWindow,
|
||||
const nsAString& aScope,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aWindow);
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
|
||||
@ -2052,7 +2067,8 @@ Notification::Get(nsPIDOMWindowInner* aWindow,
|
||||
RefPtr<NotificationGetRunnable> r =
|
||||
new NotificationGetRunnable(origin, aFilter.mTag, callback);
|
||||
|
||||
aRv = NS_DispatchToMainThread(r);
|
||||
aRv = global->Dispatch("Notification::Get", TaskCategory::Other,
|
||||
r.forget());
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -2172,7 +2188,8 @@ public:
|
||||
WorkerGetRunnable(PromiseWorkerProxy* aProxy,
|
||||
const nsAString& aTag,
|
||||
const nsAString& aScope)
|
||||
: mPromiseProxy(aProxy), mTag(aTag), mScope(aScope)
|
||||
: Runnable("WorkerGetRunnable")
|
||||
, mPromiseProxy(aProxy), mTag(aTag), mScope(aScope)
|
||||
{
|
||||
MOZ_ASSERT(mPromiseProxy);
|
||||
}
|
||||
@ -2219,6 +2236,7 @@ private:
|
||||
{}
|
||||
};
|
||||
|
||||
// static
|
||||
already_AddRefed<Promise>
|
||||
Notification::WorkerGet(WorkerPrivate* aWorkerPrivate,
|
||||
const GetNotificationOptions& aFilter,
|
||||
@ -2243,7 +2261,7 @@ Notification::WorkerGet(WorkerPrivate* aWorkerPrivate,
|
||||
new WorkerGetRunnable(proxy, aFilter.mTag, aScope);
|
||||
// Since this is called from script via
|
||||
// ServiceWorkerRegistration::GetNotifications, we can assert dispatch.
|
||||
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r));
|
||||
MOZ_ALWAYS_SUCCEEDS(aWorkerPrivate->DispatchToMainThread(r.forget()));
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
@ -2263,8 +2281,9 @@ Notification::Close()
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> closeNotificationTask =
|
||||
new NotificationTask(Move(ref), NotificationTask::eClose);
|
||||
nsresult rv = NS_DispatchToMainThread(closeNotificationTask);
|
||||
new NotificationTask("Notification::Close", Move(ref),
|
||||
NotificationTask::eClose);
|
||||
nsresult rv = DispatchToMainThread(closeNotificationTask.forget());
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
DispatchTrustedEvent(NS_LITERAL_STRING("error"));
|
||||
@ -2703,8 +2722,12 @@ Notification::CreateAndShow(JSContext* aCx,
|
||||
|
||||
// Queue a task to show the notification.
|
||||
nsCOMPtr<nsIRunnable> showNotificationTask =
|
||||
new NotificationTask(Move(ref), NotificationTask::eShow);
|
||||
nsresult rv = NS_DispatchToMainThread(showNotificationTask);
|
||||
new NotificationTask("Notification::CreateAndShow", Move(ref),
|
||||
NotificationTask::eShow);
|
||||
|
||||
nsresult rv =
|
||||
notification->DispatchToMainThread(showNotificationTask.forget());
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
notification->DispatchTrustedEvent(NS_LITERAL_STRING("error"));
|
||||
}
|
||||
@ -2763,5 +2786,22 @@ Notification::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Notification::DispatchToMainThread(already_AddRefed<nsIRunnable>&& aRunnable)
|
||||
{
|
||||
if (mWorkerPrivate) {
|
||||
return mWorkerPrivate->DispatchToMainThread(Move(aRunnable));
|
||||
}
|
||||
AssertIsOnMainThread();
|
||||
if (nsCOMPtr<nsIGlobalObject> global = GetOwnerGlobal()) {
|
||||
if (nsIEventTarget* target = global->EventTargetFor(TaskCategory::Other)) {
|
||||
return target->Dispatch(Move(aRunnable), nsIEventTarget::DISPATCH_NORMAL);
|
||||
}
|
||||
}
|
||||
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||
MOZ_ASSERT(mainThread);
|
||||
return mainThread->Dispatch(Move(aRunnable), nsIEventTarget::DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -327,6 +327,8 @@ public:
|
||||
|
||||
static nsresult RemovePermission(nsIPrincipal* aPrincipal);
|
||||
static nsresult OpenSettings(nsIPrincipal* aPrincipal);
|
||||
|
||||
nsresult DispatchToMainThread(already_AddRefed<nsIRunnable>&& aRunnable);
|
||||
protected:
|
||||
Notification(nsIGlobalObject* aGlobal, const nsAString& aID,
|
||||
const nsAString& aTitle, const nsAString& aBody,
|
||||
|
@ -10,51 +10,22 @@
|
||||
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/StyleAnimationValue.h"
|
||||
#include "nsICSSDeclaration.h"
|
||||
#include "nsSMILCSSValueType.h"
|
||||
#include "nsSMILValue.h"
|
||||
#include "nsComputedDOMStyle.h"
|
||||
#include "nsCSSProps.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsIDocument.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
// Helper function
|
||||
static bool
|
||||
GetCSSComputedValue(Element* aElem,
|
||||
nsCSSPropertyID aPropID,
|
||||
nsAString& aResult)
|
||||
{
|
||||
MOZ_ASSERT(!nsCSSProps::IsShorthand(aPropID),
|
||||
"Can't look up computed value of shorthand property");
|
||||
MOZ_ASSERT(nsSMILCSSProperty::IsPropertyAnimatable(aPropID),
|
||||
"Shouldn't get here for non-animatable properties");
|
||||
|
||||
nsIDocument* doc = aElem->GetUncomposedDoc();
|
||||
if (!doc) {
|
||||
// This can happen if we process certain types of restyles mid-sample
|
||||
// and remove anonymous animated content from the document as a result.
|
||||
// See bug 534975.
|
||||
return false;
|
||||
}
|
||||
|
||||
nsIPresShell* shell = doc->GetShell();
|
||||
if (!shell) {
|
||||
NS_WARNING("Unable to look up computed style -- no pres shell");
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<nsComputedDOMStyle> computedStyle =
|
||||
NS_NewComputedDOMStyle(aElem, EmptyString(), shell);
|
||||
|
||||
computedStyle->GetPropertyValue(aPropID, aResult);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Class Methods
|
||||
nsSMILCSSProperty::nsSMILCSSProperty(nsCSSPropertyID aPropID,
|
||||
Element* aElement)
|
||||
: mPropID(aPropID), mElement(aElement)
|
||||
Element* aElement,
|
||||
nsStyleContext* aBaseStyleContext)
|
||||
: mPropID(aPropID)
|
||||
, mElement(aElement)
|
||||
, mBaseStyleContext(aBaseStyleContext)
|
||||
{
|
||||
MOZ_ASSERT(IsPropertyAnimatable(mPropID),
|
||||
"Creating a nsSMILCSSProperty for a property "
|
||||
@ -71,7 +42,10 @@ nsSMILCSSProperty::GetBaseValue() const
|
||||
|
||||
// SPECIAL CASE: (a) Shorthands
|
||||
// (b) 'display'
|
||||
if (nsCSSProps::IsShorthand(mPropID) || mPropID == eCSSProperty_display) {
|
||||
// (c) No base style context
|
||||
if (nsCSSProps::IsShorthand(mPropID) ||
|
||||
mPropID == eCSSProperty_display ||
|
||||
!mBaseStyleContext) {
|
||||
// We can't look up the base (computed-style) value of shorthand
|
||||
// properties because they aren't guaranteed to have a consistent computed
|
||||
// value.
|
||||
@ -80,47 +54,26 @@ nsSMILCSSProperty::GetBaseValue() const
|
||||
// doing so involves clearing and resetting the property which can cause
|
||||
// frames to be recreated which we'd like to avoid.
|
||||
//
|
||||
// In either case, just return a dummy value (initialized with the right
|
||||
// Furthermore, if we don't (yet) have a base style context we obviously
|
||||
// can't resolve a base value.
|
||||
//
|
||||
// In any case, just return a dummy value (initialized with the right
|
||||
// type, so as not to indicate failure).
|
||||
nsSMILValue tmpVal(&nsSMILCSSValueType::sSingleton);
|
||||
Swap(baseValue, tmpVal);
|
||||
return baseValue;
|
||||
}
|
||||
|
||||
// GENERAL CASE: Non-Shorthands
|
||||
// (1) Put empty string in override style for property mPropID
|
||||
// (saving old override style value, so we can set it again when we're done)
|
||||
nsICSSDeclaration* overrideDecl = mElement->GetSMILOverrideStyle();
|
||||
nsAutoString cachedOverrideStyleVal;
|
||||
if (overrideDecl) {
|
||||
overrideDecl->GetPropertyValue(mPropID, cachedOverrideStyleVal);
|
||||
// (Don't bother clearing override style if it's already empty)
|
||||
if (!cachedOverrideStyleVal.IsEmpty()) {
|
||||
overrideDecl->SetPropertyValue(mPropID, EmptyString());
|
||||
}
|
||||
StyleAnimationValue computedValue;
|
||||
if (!StyleAnimationValue::ExtractComputedValue(mPropID,
|
||||
mBaseStyleContext,
|
||||
computedValue)) {
|
||||
return baseValue;
|
||||
}
|
||||
|
||||
// (2) Get Computed Style
|
||||
nsAutoString computedStyleVal;
|
||||
bool didGetComputedVal = GetCSSComputedValue(mElement, mPropID,
|
||||
computedStyleVal);
|
||||
|
||||
// (3) Put cached override style back (if it's non-empty)
|
||||
if (overrideDecl && !cachedOverrideStyleVal.IsEmpty()) {
|
||||
overrideDecl->SetPropertyValue(mPropID, cachedOverrideStyleVal);
|
||||
}
|
||||
|
||||
// (4) Populate our nsSMILValue from the computed style
|
||||
if (didGetComputedVal) {
|
||||
// When we parse animation values we check if they are context-sensitive or
|
||||
// not so that we don't cache animation values whose meaning may change.
|
||||
// For base values however this is unnecessary since on each sample the
|
||||
// compositor will fetch the (computed) base value and compare it against
|
||||
// the cached (computed) value and detect changes for us.
|
||||
nsSMILCSSValueType::ValueFromString(mPropID, mElement,
|
||||
computedStyleVal, baseValue,
|
||||
nullptr);
|
||||
}
|
||||
baseValue =
|
||||
nsSMILCSSValueType::ValueFromAnimationValue(mPropID, mElement,
|
||||
computedValue);
|
||||
return baseValue;
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include "nsCSSPropertyID.h"
|
||||
#include "nsCSSValue.h"
|
||||
|
||||
class nsStyleContext;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class Element;
|
||||
@ -33,8 +35,14 @@ public:
|
||||
* Constructs a new nsSMILCSSProperty.
|
||||
* @param aPropID The CSS property we're interested in animating.
|
||||
* @param aElement The element whose CSS property is being animated.
|
||||
* @param aBaseStyleContext The style context to use when getting the base
|
||||
* value. If this is nullptr and GetBaseValue is
|
||||
* called, an empty nsSMILValue initialized with
|
||||
* the nsSMILCSSValueType will be returned.
|
||||
*/
|
||||
nsSMILCSSProperty(nsCSSPropertyID aPropID, mozilla::dom::Element* aElement);
|
||||
nsSMILCSSProperty(nsCSSPropertyID aPropID,
|
||||
mozilla::dom::Element* aElement,
|
||||
nsStyleContext* aBaseStyleContext);
|
||||
|
||||
// nsISMILAttr methods
|
||||
virtual nsresult ValueFromString(const nsAString& aStr,
|
||||
@ -62,6 +70,12 @@ protected:
|
||||
// as the Compositing step, and DOM elements don't get a chance to die during
|
||||
// that time.
|
||||
mozilla::dom::Element* mElement;
|
||||
|
||||
// The style context to use when fetching base styles.
|
||||
// As with mElement, since an nsISMILAttr only lives as long as the
|
||||
// compositing step and since ComposeAttribute holds an owning reference to
|
||||
// the base style context, we can use a non-owning reference here.
|
||||
nsStyleContext* mBaseStyleContext;
|
||||
};
|
||||
|
||||
#endif // NS_SMILCSSPROPERTY_H_
|
||||
|
@ -7,6 +7,8 @@
|
||||
/* representation of a value for a SMIL-animated CSS property */
|
||||
|
||||
#include "nsSMILCSSValueType.h"
|
||||
|
||||
#include "nsComputedDOMStyle.h"
|
||||
#include "nsString.h"
|
||||
#include "nsSMILParserUtils.h"
|
||||
#include "nsSMILValue.h"
|
||||
@ -361,8 +363,8 @@ ValueFromStringHelper(nsCSSPropertyID aPropID,
|
||||
}
|
||||
}
|
||||
RefPtr<nsStyleContext> styleContext =
|
||||
nsComputedDOMStyle::GetStyleContextForElement(aTargetElement, nullptr,
|
||||
aPresContext->PresShell());
|
||||
nsComputedDOMStyle::GetStyleContext(aTargetElement, nullptr,
|
||||
aPresContext->PresShell());
|
||||
if (!styleContext) {
|
||||
return false;
|
||||
}
|
||||
@ -417,6 +419,34 @@ nsSMILCSSValueType::ValueFromString(nsCSSPropertyID aPropID,
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
nsSMILValue
|
||||
nsSMILCSSValueType::ValueFromAnimationValue(nsCSSPropertyID aPropID,
|
||||
Element* aTargetElement,
|
||||
const StyleAnimationValue& aValue)
|
||||
{
|
||||
nsSMILValue result;
|
||||
|
||||
nsIDocument* doc = aTargetElement->GetUncomposedDoc();
|
||||
// We'd like to avoid serializing |aValue| if possible, and since the
|
||||
// string passed to CSPAllowsInlineStyle is only used for reporting violations
|
||||
// and an intermediate CSS value is not likely to be particularly useful
|
||||
// in that case, we just use a generic placeholder string instead.
|
||||
static const nsLiteralString kPlaceholderText =
|
||||
NS_LITERAL_STRING("[SVG animation of CSS]");
|
||||
if (doc && !nsStyleUtil::CSPAllowsInlineStyle(nullptr,
|
||||
doc->NodePrincipal(),
|
||||
doc->GetDocumentURI(),
|
||||
0, kPlaceholderText, nullptr)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
sSingleton.Init(result);
|
||||
result.mU.mPtr = new ValueWrapper(aPropID, aValue);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
nsSMILCSSValueType::ValueToString(const nsSMILValue& aValue,
|
||||
|
@ -16,6 +16,7 @@
|
||||
class nsAString;
|
||||
|
||||
namespace mozilla {
|
||||
class StyleAnimationValue;
|
||||
namespace dom {
|
||||
class Element;
|
||||
} // namespace dom
|
||||
@ -28,6 +29,7 @@ class nsSMILCSSValueType : public nsISMILType
|
||||
{
|
||||
public:
|
||||
typedef mozilla::dom::Element Element;
|
||||
typedef mozilla::StyleAnimationValue StyleAnimationValue;
|
||||
|
||||
// Singleton for nsSMILValue objects to hold onto.
|
||||
static nsSMILCSSValueType sSingleton;
|
||||
@ -84,6 +86,21 @@ public:
|
||||
nsSMILValue& aValue,
|
||||
bool* aIsContextSensitive);
|
||||
|
||||
/**
|
||||
* Creates an nsSMILValue to wrap the given animation value.
|
||||
*
|
||||
* @param aPropID The property that |aValue| corresponds to.
|
||||
* @param aTargetElement The target element to which the animation value
|
||||
* applies.
|
||||
* @param aValue The animation value to use.
|
||||
* @return A new nsSMILValue. On failure, returns an
|
||||
* nsSMILValue with the null type (i.e. rv.IsNull()
|
||||
* returns true).
|
||||
*/
|
||||
static nsSMILValue ValueFromAnimationValue(nsCSSPropertyID aPropID,
|
||||
Element* aTargetElement,
|
||||
const StyleAnimationValue& aValue);
|
||||
|
||||
/**
|
||||
* Creates a string representation of the given nsSMILValue.
|
||||
*
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "nsSMILCompositor.h"
|
||||
|
||||
#include "nsComputedDOMStyle.h"
|
||||
#include "nsCSSProps.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsSMILCSSProperty.h"
|
||||
@ -54,9 +55,18 @@ nsSMILCompositor::ComposeAttribute(bool& aMightHavePendingStyleUpdates)
|
||||
if (!mKey.mElement)
|
||||
return;
|
||||
|
||||
// If we might need to resolve base styles, grab a suitable style context
|
||||
// for initializing our nsISMILAttr with.
|
||||
RefPtr<nsStyleContext> baseStyleContext;
|
||||
if (MightNeedBaseStyle()) {
|
||||
baseStyleContext =
|
||||
nsComputedDOMStyle::GetUnanimatedStyleContextNoFlush(mKey.mElement,
|
||||
nullptr, nullptr);
|
||||
}
|
||||
|
||||
// FIRST: Get the nsISMILAttr (to grab base value from, and to eventually
|
||||
// give animated value to)
|
||||
UniquePtr<nsISMILAttr> smilAttr = CreateSMILAttr();
|
||||
UniquePtr<nsISMILAttr> smilAttr = CreateSMILAttr(baseStyleContext);
|
||||
if (!smilAttr) {
|
||||
// Target attribute not found (or, out of memory)
|
||||
return;
|
||||
@ -115,7 +125,7 @@ nsSMILCompositor::ClearAnimationEffects()
|
||||
if (!mKey.mElement || !mKey.mAttributeName)
|
||||
return;
|
||||
|
||||
UniquePtr<nsISMILAttr> smilAttr = CreateSMILAttr();
|
||||
UniquePtr<nsISMILAttr> smilAttr = CreateSMILAttr(nullptr);
|
||||
if (!smilAttr) {
|
||||
// Target attribute not found (or, out of memory)
|
||||
return;
|
||||
@ -126,12 +136,13 @@ nsSMILCompositor::ClearAnimationEffects()
|
||||
// Protected Helper Functions
|
||||
// --------------------------
|
||||
UniquePtr<nsISMILAttr>
|
||||
nsSMILCompositor::CreateSMILAttr()
|
||||
nsSMILCompositor::CreateSMILAttr(nsStyleContext* aBaseStyleContext)
|
||||
{
|
||||
nsCSSPropertyID propID = GetCSSPropertyToAnimate();
|
||||
|
||||
if (propID != eCSSProperty_UNKNOWN) {
|
||||
return MakeUnique<nsSMILCSSProperty>(propID, mKey.mElement.get());
|
||||
return MakeUnique<nsSMILCSSProperty>(propID, mKey.mElement.get(),
|
||||
aBaseStyleContext);
|
||||
}
|
||||
|
||||
return mKey.mElement->GetAnimatedAttr(mKey.mAttributeNamespaceID,
|
||||
@ -173,6 +184,24 @@ nsSMILCompositor::GetCSSPropertyToAnimate() const
|
||||
return propID;
|
||||
}
|
||||
|
||||
bool
|
||||
nsSMILCompositor::MightNeedBaseStyle() const
|
||||
{
|
||||
if (GetCSSPropertyToAnimate() == eCSSProperty_UNKNOWN) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We should return true if at least one animation function might build on
|
||||
// the base value.
|
||||
for (const nsSMILAnimationFunction* func : mAnimationFunctions) {
|
||||
if (!func->WillReplace()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
nsSMILCompositor::GetFirstFuncToAffectSandwich()
|
||||
{
|
||||
|
@ -74,12 +74,26 @@ public:
|
||||
|
||||
private:
|
||||
// Create a nsISMILAttr for my target, on the heap.
|
||||
mozilla::UniquePtr<nsISMILAttr> CreateSMILAttr();
|
||||
//
|
||||
// @param aBaseStyleContext An optional style context which, if set, will be
|
||||
// used when fetching the base style.
|
||||
mozilla::UniquePtr<nsISMILAttr>
|
||||
CreateSMILAttr(nsStyleContext* aBaseStyleContext);
|
||||
|
||||
// Returns the CSS property this compositor should animate, or
|
||||
// eCSSProperty_UNKNOWN if this compositor does not animate a CSS property.
|
||||
nsCSSPropertyID GetCSSPropertyToAnimate() const;
|
||||
|
||||
// Returns true if we might need to refer to base styles (i.e. we are
|
||||
// targeting a CSS property and have one or more animation functions that
|
||||
// don't just replace the underlying value).
|
||||
//
|
||||
// This might return true in some cases where we don't actually need the base
|
||||
// style since it doesn't build up the animation sandwich to check if the
|
||||
// functions that appear to need the base style are actually replaced by
|
||||
// a function further up the stack.
|
||||
bool MightNeedBaseStyle() const;
|
||||
|
||||
// Finds the index of the first function that will affect our animation
|
||||
// sandwich. Also toggles the 'mForceCompositing' flag if it finds that any
|
||||
// (used) functions have changed.
|
||||
|
@ -57,5 +57,6 @@ skip-if = toolkit == 'android' #TIMED_OUT
|
||||
[test_smilTimingZeroIntervals.xhtml]
|
||||
[test_smilUpdatedInterval.xhtml]
|
||||
[test_smilValues.xhtml]
|
||||
[test_smilWithTransition.html]
|
||||
[test_smilWithXlink.xhtml]
|
||||
[test_smilXHR.xhtml]
|
||||
|
72
dom/smil/test/test_smilWithTransition.html
Normal file
72
dom/smil/test/test_smilWithTransition.html
Normal file
@ -0,0 +1,72 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1315874
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test SMIL does not trigger CSS Transitions (bug 1315874)</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1315874">Mozilla Bug
|
||||
1315874</a>
|
||||
<svg>
|
||||
<rect width="100%" height="100%"
|
||||
style="fill: red; transition: fill 10s" id="rect">
|
||||
<animate attributeName="fill" to="lime" dur="1s" fill="freeze">
|
||||
</rect>
|
||||
</svg>
|
||||
<pre id="test">
|
||||
<script type="text/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
window.addEventListener('load', runTests, false);
|
||||
|
||||
var rect = document.getElementById('rect');
|
||||
var svg = document.getElementsByTagName('svg')[0];
|
||||
is(getComputedStyle(rect).fill, 'rgb(255, 0, 0)',
|
||||
'The initial color should be red.');
|
||||
|
||||
function runTests() {
|
||||
waitForFrame().then(function() {
|
||||
svg.setCurrentTime(1);
|
||||
ok(getComputedStyle(rect).fill, 'rgb(0, 255, 0)',
|
||||
'The end color should be lime.');
|
||||
|
||||
return waitForAnimationFrames(2);
|
||||
}).then(function() {
|
||||
var anim = document.getAnimations()[0];
|
||||
ok(!anim, 'Transition should not be created by restyling for SMIL');
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
// Utility methods from testcommon.js
|
||||
// For detail, see dom/animation/test/testcommon.js.
|
||||
|
||||
function waitForFrame() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
requestAnimationFrame(function(time) {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function waitForAnimationFrames(frameCount) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
function handleFrame() {
|
||||
if (--frameCount <= 0) {
|
||||
resolve();
|
||||
} else {
|
||||
window.requestAnimationFrame(handleFrame);
|
||||
}
|
||||
}
|
||||
window.requestAnimationFrame(handleFrame);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -179,8 +179,7 @@ SVGContentUtils::GetStrokeOptions(AutoStrokeOptions* aStrokeOptions,
|
||||
styleContext = aStyleContext;
|
||||
} else {
|
||||
styleContext =
|
||||
nsComputedDOMStyle::GetStyleContextForElementNoFlush(aElement, nullptr,
|
||||
nullptr);
|
||||
nsComputedDOMStyle::GetStyleContextNoFlush(aElement, nullptr, nullptr);
|
||||
}
|
||||
|
||||
if (!styleContext) {
|
||||
@ -253,8 +252,7 @@ SVGContentUtils::GetStrokeWidth(nsSVGElement* aElement,
|
||||
styleContext = aStyleContext;
|
||||
} else {
|
||||
styleContext =
|
||||
nsComputedDOMStyle::GetStyleContextForElementNoFlush(aElement, nullptr,
|
||||
nullptr);
|
||||
nsComputedDOMStyle::GetStyleContextNoFlush(aElement, nullptr, nullptr);
|
||||
}
|
||||
|
||||
if (!styleContext) {
|
||||
@ -276,9 +274,8 @@ SVGContentUtils::GetFontSize(Element *aElement)
|
||||
if (!aElement)
|
||||
return 1.0f;
|
||||
|
||||
RefPtr<nsStyleContext> styleContext =
|
||||
nsComputedDOMStyle::GetStyleContextForElementNoFlush(aElement,
|
||||
nullptr, nullptr);
|
||||
RefPtr<nsStyleContext> styleContext =
|
||||
nsComputedDOMStyle::GetStyleContextNoFlush(aElement, nullptr, nullptr);
|
||||
if (!styleContext) {
|
||||
// ReportToConsole
|
||||
NS_WARNING("Couldn't get style context for content in GetFontStyle");
|
||||
@ -314,9 +311,8 @@ SVGContentUtils::GetFontXHeight(Element *aElement)
|
||||
if (!aElement)
|
||||
return 1.0f;
|
||||
|
||||
RefPtr<nsStyleContext> styleContext =
|
||||
nsComputedDOMStyle::GetStyleContextForElementNoFlush(aElement,
|
||||
nullptr, nullptr);
|
||||
RefPtr<nsStyleContext> styleContext =
|
||||
nsComputedDOMStyle::GetStyleContextNoFlush(aElement, nullptr, nullptr);
|
||||
if (!styleContext) {
|
||||
// ReportToConsole
|
||||
NS_WARNING("Couldn't get style context for content in GetFontStyle");
|
||||
@ -325,7 +321,7 @@ SVGContentUtils::GetFontXHeight(Element *aElement)
|
||||
|
||||
return GetFontXHeight(styleContext);
|
||||
}
|
||||
|
||||
|
||||
float
|
||||
SVGContentUtils::GetFontXHeight(nsIFrame *aFrame)
|
||||
{
|
||||
|
@ -127,9 +127,8 @@ SVGGeometryElement::GetFillRule()
|
||||
FillRule fillRule = FillRule::FILL_WINDING; // Equivalent to StyleFillRule::Nonzero
|
||||
|
||||
RefPtr<nsStyleContext> styleContext =
|
||||
nsComputedDOMStyle::GetStyleContextForElementNoFlush(this, nullptr,
|
||||
nullptr);
|
||||
|
||||
nsComputedDOMStyle::GetStyleContextNoFlush(this, nullptr, nullptr);
|
||||
|
||||
if (styleContext) {
|
||||
MOZ_ASSERT(styleContext->StyleSVG()->mFillRule == StyleFillRule::Nonzero ||
|
||||
styleContext->StyleSVG()->mFillRule == StyleFillRule::Evenodd);
|
||||
|
@ -328,7 +328,7 @@ SVGPathElement::BuildPath(PathBuilder* aBuilder)
|
||||
Float strokeWidth = 0;
|
||||
|
||||
RefPtr<nsStyleContext> styleContext =
|
||||
nsComputedDOMStyle::GetStyleContextForElementNoFlush(this, nullptr, nullptr);
|
||||
nsComputedDOMStyle::GetStyleContextNoFlush(this, nullptr, nullptr);
|
||||
if (styleContext) {
|
||||
const nsStyleSVG* style = styleContext->StyleSVG();
|
||||
// Note: the path that we return may be used for hit-testing, and SVG
|
||||
|
@ -596,9 +596,9 @@ var interfaceNamesInGlobalScope =
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"InstallTrigger",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "IntersectionObserver", disabled: true},
|
||||
"IntersectionObserver",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "IntersectionObserverEntry", disabled: true},
|
||||
"IntersectionObserverEntry",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"KeyEvent",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
@ -3535,8 +3535,7 @@ IsElementVisible(Element* aElement)
|
||||
// lazy frame construction and it hasn't happened yet. Check which
|
||||
// one it is.
|
||||
RefPtr<nsStyleContext> styleContext =
|
||||
nsComputedDOMStyle::GetStyleContextForElementNoFlush(aElement,
|
||||
nullptr, nullptr);
|
||||
nsComputedDOMStyle::GetStyleContextNoFlush(aElement, nullptr, nullptr);
|
||||
if (styleContext) {
|
||||
return styleContext->StyleDisplay()->mDisplay != StyleDisplay::None;
|
||||
}
|
||||
@ -3867,9 +3866,9 @@ EditorBase::IsPreformatted(nsIDOMNode* aNode,
|
||||
content = content->GetParent();
|
||||
}
|
||||
if (content && content->IsElement()) {
|
||||
elementStyle = nsComputedDOMStyle::GetStyleContextForElementNoFlush(content->AsElement(),
|
||||
nullptr,
|
||||
ps);
|
||||
elementStyle =
|
||||
nsComputedDOMStyle::GetStyleContextNoFlush(content->AsElement(),
|
||||
nullptr, ps);
|
||||
}
|
||||
|
||||
if (!elementStyle) {
|
||||
|
@ -1,37 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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_mscom_IHandlerPayload_h
|
||||
#define mozilla_mscom_IHandlerPayload_h
|
||||
|
||||
#include "mozilla/mscom/Ptr.h"
|
||||
|
||||
#include <objidl.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace mscom {
|
||||
|
||||
struct HandlerPayload
|
||||
{
|
||||
virtual STDMETHODIMP GetHandler(CLSID* aHandlerClsid) = 0;
|
||||
virtual STDMETHODIMP GetHandlerPayloadSize(REFIID aIid,
|
||||
InterceptorTargetPtr<IUnknown> aTarget,
|
||||
DWORD* aOutPayloadSize) = 0;
|
||||
virtual STDMETHODIMP WriteHandlerPayload(IStream* aStream, REFIID aIid,
|
||||
InterceptorTargetPtr<IUnknown> aTarget) = 0;
|
||||
virtual REFIID MarshalAs(REFIID aIid) = 0;
|
||||
};
|
||||
|
||||
struct IHandlerPayload : public IUnknown
|
||||
, public HandlerPayload
|
||||
{
|
||||
virtual STDMETHODIMP Clone(IHandlerPayload** aOutNewPayload) = 0;
|
||||
};
|
||||
|
||||
} // namespace mscom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_mscom_IHandlerPayload_h
|
37
ipc/mscom/IHandlerProvider.h
Normal file
37
ipc/mscom/IHandlerProvider.h
Normal file
@ -0,0 +1,37 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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_mscom_IHandlerProvider_h
|
||||
#define mozilla_mscom_IHandlerProvider_h
|
||||
|
||||
#include "mozilla/NotNull.h"
|
||||
#include "mozilla/mscom/Ptr.h"
|
||||
|
||||
#include <objidl.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace mscom {
|
||||
|
||||
struct HandlerProvider
|
||||
{
|
||||
virtual STDMETHODIMP GetHandler(NotNull<CLSID*> aHandlerClsid) = 0;
|
||||
virtual STDMETHODIMP GetHandlerPayloadSize(NotNull<DWORD*> aOutPayloadSize) = 0;
|
||||
virtual STDMETHODIMP WriteHandlerPayload(NotNull<IStream*> aStream) = 0;
|
||||
virtual STDMETHODIMP_(REFIID) MarshalAs(REFIID aIid) = 0;
|
||||
};
|
||||
|
||||
struct IHandlerProvider : public IUnknown
|
||||
, public HandlerProvider
|
||||
{
|
||||
virtual STDMETHODIMP NewInstance(REFIID aIid,
|
||||
InterceptorTargetPtr<IUnknown> aTarget,
|
||||
NotNull<IHandlerProvider**> aOutNewPayload) = 0;
|
||||
};
|
||||
|
||||
} // namespace mscom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_mscom_IHandlerProvider_h
|
@ -78,7 +78,7 @@ Interceptor::GetClassForHandler(DWORD aDestContext, void* aDestContextPtr,
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
MOZ_ASSERT(mEventSink);
|
||||
return mEventSink->GetHandler(aHandlerClsid);
|
||||
return mEventSink->GetHandler(WrapNotNull(aHandlerClsid));
|
||||
}
|
||||
|
||||
HRESULT
|
||||
@ -101,10 +101,8 @@ Interceptor::GetMarshalSizeMax(REFIID riid, void* pv, DWORD dwDestContext,
|
||||
return hr;
|
||||
}
|
||||
|
||||
InterceptorTargetPtr<IUnknown> targetParam(mTarget.get());
|
||||
|
||||
DWORD payloadSize = 0;
|
||||
hr = mEventSink->GetHandlerPayloadSize(riid, Move(targetParam), &payloadSize);
|
||||
hr = mEventSink->GetHandlerPayloadSize(WrapNotNull(&payloadSize));
|
||||
*pSize += payloadSize;
|
||||
return hr;
|
||||
}
|
||||
@ -120,8 +118,7 @@ Interceptor::MarshalInterface(IStream* pStm, REFIID riid, void* pv,
|
||||
return hr;
|
||||
}
|
||||
|
||||
InterceptorTargetPtr<IUnknown> targetParam(mTarget.get());
|
||||
return mEventSink->WriteHandlerPayload(pStm, riid, Move(targetParam));
|
||||
return mEventSink->WriteHandlerPayload(WrapNotNull(pStm));
|
||||
}
|
||||
|
||||
HRESULT
|
||||
@ -367,7 +364,7 @@ Interceptor::ThreadSafeQueryInterface(REFIID aIid, IUnknown** aOutInterface)
|
||||
// support it. We'll check that by looking for a successful call to
|
||||
// IInterceptorSink::GetHandler()
|
||||
CLSID dummy;
|
||||
if (FAILED(mEventSink->GetHandler(&dummy))) {
|
||||
if (FAILED(mEventSink->GetHandler(WrapNotNull(&dummy)))) {
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
@ -381,7 +378,7 @@ Interceptor::ThreadSafeQueryInterface(REFIID aIid, IUnknown** aOutInterface)
|
||||
// support it. We'll check that by looking for a successful call to
|
||||
// IInterceptorSink::GetHandler()
|
||||
CLSID dummy;
|
||||
if (FAILED(mEventSink->GetHandler(&dummy))) {
|
||||
if (FAILED(mEventSink->GetHandler(WrapNotNull(&dummy)))) {
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/mscom/IHandlerPayload.h"
|
||||
#include "mozilla/mscom/IHandlerProvider.h"
|
||||
#include "mozilla/mscom/Ptr.h"
|
||||
#include "mozilla/mscom/WeakRef.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
@ -26,7 +26,7 @@ DEFINE_GUID(IID_IInterceptorSink,
|
||||
0x8831eb53, 0xa937, 0x42bc, 0x99, 0x21, 0xb3, 0xe1, 0x12, 0x1f, 0xdf, 0x86);
|
||||
|
||||
struct IInterceptorSink : public ICallFrameEvents
|
||||
, public HandlerPayload
|
||||
, public HandlerProvider
|
||||
{
|
||||
virtual STDMETHODIMP SetInterceptor(IWeakReference* aInterceptor) = 0;
|
||||
};
|
||||
|
@ -159,16 +159,16 @@ namespace mozilla {
|
||||
namespace mscom {
|
||||
|
||||
/* static */ HRESULT
|
||||
MainThreadHandoff::Create(IHandlerPayload* aHandlerPayload,
|
||||
MainThreadHandoff::Create(IHandlerProvider* aHandlerProvider,
|
||||
IInterceptorSink** aOutput)
|
||||
{
|
||||
RefPtr<MainThreadHandoff> handoff(new MainThreadHandoff(aHandlerPayload));
|
||||
RefPtr<MainThreadHandoff> handoff(new MainThreadHandoff(aHandlerProvider));
|
||||
return handoff->QueryInterface(IID_IInterceptorSink, (void**) aOutput);
|
||||
}
|
||||
|
||||
MainThreadHandoff::MainThreadHandoff(IHandlerPayload* aHandlerPayload)
|
||||
MainThreadHandoff::MainThreadHandoff(IHandlerProvider* aHandlerProvider)
|
||||
: mRefCnt(0)
|
||||
, mHandlerPayload(aHandlerPayload)
|
||||
, mHandlerProvider(aHandlerProvider)
|
||||
{
|
||||
}
|
||||
|
||||
@ -448,43 +448,39 @@ MainThreadHandoff::SetInterceptor(IWeakReference* aInterceptor)
|
||||
}
|
||||
|
||||
HRESULT
|
||||
MainThreadHandoff::GetHandler(CLSID* aHandlerClsid)
|
||||
MainThreadHandoff::GetHandler(NotNull<CLSID*> aHandlerClsid)
|
||||
{
|
||||
if (!mHandlerPayload) {
|
||||
if (!mHandlerProvider) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
return mHandlerPayload->GetHandler(aHandlerClsid);
|
||||
return mHandlerProvider->GetHandler(aHandlerClsid);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
MainThreadHandoff::GetHandlerPayloadSize(REFIID aIid,
|
||||
InterceptorTargetPtr<IUnknown> aTarget,
|
||||
DWORD* aOutPayloadSize)
|
||||
MainThreadHandoff::GetHandlerPayloadSize(NotNull<DWORD*> aOutPayloadSize)
|
||||
{
|
||||
if (!mHandlerPayload) {
|
||||
if (!mHandlerProvider) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
return mHandlerPayload->GetHandlerPayloadSize(aIid, Move(aTarget),
|
||||
aOutPayloadSize);
|
||||
return mHandlerProvider->GetHandlerPayloadSize(aOutPayloadSize);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
MainThreadHandoff::WriteHandlerPayload(IStream* aStream, REFIID aIid,
|
||||
InterceptorTargetPtr<IUnknown> aTarget)
|
||||
MainThreadHandoff::WriteHandlerPayload(NotNull<IStream*> aStream)
|
||||
{
|
||||
if (!mHandlerPayload) {
|
||||
if (!mHandlerProvider) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
return mHandlerPayload->WriteHandlerPayload(aStream, aIid, Move(aTarget));
|
||||
return mHandlerProvider->WriteHandlerPayload(aStream);
|
||||
}
|
||||
|
||||
REFIID
|
||||
MainThreadHandoff::MarshalAs(REFIID aIid)
|
||||
{
|
||||
if (!mHandlerPayload) {
|
||||
if (!mHandlerProvider) {
|
||||
return aIid;
|
||||
}
|
||||
return mHandlerPayload->MarshalAs(aIid);
|
||||
return mHandlerProvider->MarshalAs(aIid);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
@ -529,24 +525,31 @@ MainThreadHandoff::OnWalkInterface(REFIID aIid, PVOID* aInterface,
|
||||
InterceptorTargetPtr<IUnknown> existingTarget;
|
||||
hr = interceptor->GetTargetForIID(aIid, existingTarget);
|
||||
if (SUCCEEDED(hr)) {
|
||||
bool areIUnknownsEqual = false;
|
||||
// We'll start by checking the raw pointers. If they are equal, then the
|
||||
// objects are equal. OTOH, if they differ, we must compare their
|
||||
// IUnknown pointers to know for sure.
|
||||
bool areTargetsEqual = existingTarget.get() == origInterface.get();
|
||||
|
||||
// This check must be done on the main thread
|
||||
auto checkFn = [&existingTarget, &origInterface, &areIUnknownsEqual]() -> void {
|
||||
RefPtr<IUnknown> unkExisting;
|
||||
HRESULT hrExisting =
|
||||
existingTarget->QueryInterface(IID_IUnknown,
|
||||
(void**)getter_AddRefs(unkExisting));
|
||||
RefPtr<IUnknown> unkNew;
|
||||
HRESULT hrNew =
|
||||
origInterface->QueryInterface(IID_IUnknown,
|
||||
(void**)getter_AddRefs(unkNew));
|
||||
areIUnknownsEqual = SUCCEEDED(hrExisting) && SUCCEEDED(hrNew) &&
|
||||
if (!areTargetsEqual) {
|
||||
// This check must be done on the main thread
|
||||
auto checkFn = [&existingTarget, &origInterface, &areTargetsEqual]() -> void {
|
||||
RefPtr<IUnknown> unkExisting;
|
||||
HRESULT hrExisting =
|
||||
existingTarget->QueryInterface(IID_IUnknown,
|
||||
(void**)getter_AddRefs(unkExisting));
|
||||
RefPtr<IUnknown> unkNew;
|
||||
HRESULT hrNew =
|
||||
origInterface->QueryInterface(IID_IUnknown,
|
||||
(void**)getter_AddRefs(unkNew));
|
||||
areTargetsEqual = SUCCEEDED(hrExisting) && SUCCEEDED(hrNew) &&
|
||||
unkExisting == unkNew;
|
||||
};
|
||||
};
|
||||
|
||||
MainThreadInvoker invoker;
|
||||
if (invoker.Invoke(NS_NewRunnableFunction(checkFn)) && areIUnknownsEqual) {
|
||||
MainThreadInvoker invoker;
|
||||
invoker.Invoke(NS_NewRunnableFunction(checkFn));
|
||||
}
|
||||
|
||||
if (areTargetsEqual) {
|
||||
// The existing interface and the new interface both belong to the same
|
||||
// target object. Let's just use the existing one.
|
||||
void* intercepted = nullptr;
|
||||
@ -560,9 +563,11 @@ MainThreadHandoff::OnWalkInterface(REFIID aIid, PVOID* aInterface,
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<IHandlerPayload> payload;
|
||||
if (mHandlerPayload) {
|
||||
hr = mHandlerPayload->Clone(getter_AddRefs(payload));
|
||||
RefPtr<IHandlerProvider> payload;
|
||||
if (mHandlerProvider) {
|
||||
hr = mHandlerProvider->NewInstance(aIid,
|
||||
ToInterceptorTargetPtr(origInterface),
|
||||
WrapNotNull((IHandlerProvider**)getter_AddRefs(payload)));
|
||||
MOZ_ASSERT(SUCCEEDED(hr));
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
|
@ -24,7 +24,7 @@ class MainThreadHandoff final : public IInterceptorSink
|
||||
, public ICallFrameWalker
|
||||
{
|
||||
public:
|
||||
static HRESULT Create(IHandlerPayload* aHandlerPayload,
|
||||
static HRESULT Create(IHandlerProvider* aHandlerProvider,
|
||||
IInterceptorSink** aOutput);
|
||||
|
||||
template <typename Interface>
|
||||
@ -37,12 +37,12 @@ public:
|
||||
|
||||
template <typename Interface>
|
||||
static HRESULT WrapInterface(STAUniquePtr<Interface> aTargetInterface,
|
||||
IHandlerPayload* aHandlerPayload,
|
||||
IHandlerProvider* aHandlerProvider,
|
||||
Interface** aOutInterface)
|
||||
{
|
||||
MOZ_ASSERT(!IsProxy(aTargetInterface.get()));
|
||||
RefPtr<IInterceptorSink> handoff;
|
||||
HRESULT hr = MainThreadHandoff::Create(aHandlerPayload,
|
||||
HRESULT hr = MainThreadHandoff::Create(aHandlerProvider,
|
||||
getter_AddRefs(handoff));
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
@ -60,29 +60,26 @@ public:
|
||||
|
||||
// IInterceptorSink
|
||||
STDMETHODIMP SetInterceptor(IWeakReference* aInterceptor) override;
|
||||
STDMETHODIMP GetHandler(CLSID* aHandlerClsid) override;
|
||||
STDMETHODIMP GetHandlerPayloadSize(REFIID aIid,
|
||||
InterceptorTargetPtr<IUnknown> aTarget,
|
||||
DWORD* aOutPayloadSize) override;
|
||||
STDMETHODIMP WriteHandlerPayload(IStream* aStream, REFIID aIid,
|
||||
InterceptorTargetPtr<IUnknown> aTarget) override;
|
||||
REFIID MarshalAs(REFIID aIid) override;
|
||||
STDMETHODIMP GetHandler(NotNull<CLSID*> aHandlerClsid) override;
|
||||
STDMETHODIMP GetHandlerPayloadSize(NotNull<DWORD*> aOutPayloadSize) override;
|
||||
STDMETHODIMP WriteHandlerPayload(NotNull<IStream*> aStream) override;
|
||||
STDMETHODIMP_(REFIID) MarshalAs(REFIID aIid) override;
|
||||
|
||||
// ICallFrameWalker
|
||||
STDMETHODIMP OnWalkInterface(REFIID aIid, PVOID* aInterface, BOOL aIsInParam,
|
||||
BOOL aIsOutParam) override;
|
||||
|
||||
private:
|
||||
explicit MainThreadHandoff(IHandlerPayload* aHandlerPayload);
|
||||
explicit MainThreadHandoff(IHandlerProvider* aHandlerProvider);
|
||||
~MainThreadHandoff();
|
||||
HRESULT FixArrayElements(ICallFrame* aFrame,
|
||||
const ArrayData& aArrayData);
|
||||
HRESULT FixIServiceProvider(ICallFrame* aFrame);
|
||||
|
||||
private:
|
||||
ULONG mRefCnt;
|
||||
RefPtr<IWeakReference> mInterceptor;
|
||||
RefPtr<IHandlerPayload> mHandlerPayload;
|
||||
ULONG mRefCnt;
|
||||
RefPtr<IWeakReference> mInterceptor;
|
||||
RefPtr<IHandlerProvider> mHandlerProvider;
|
||||
};
|
||||
|
||||
} // namespace mscom
|
||||
|
@ -153,6 +153,14 @@ ToSTAUniquePtr(RefPtr<T>&& aRefPtr)
|
||||
return STAUniquePtr<T>(aRefPtr.forget().take());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline STAUniquePtr<T>
|
||||
ToSTAUniquePtr(const RefPtr<T>& aRefPtr)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return STAUniquePtr<T>(do_AddRef(aRefPtr).take());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline STAUniquePtr<T>
|
||||
ToSTAUniquePtr(T* aRawPtr)
|
||||
@ -164,6 +172,15 @@ ToSTAUniquePtr(T* aRawPtr)
|
||||
return STAUniquePtr<T>(aRawPtr);
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
inline STAUniquePtr<T>
|
||||
ToSTAUniquePtr(const InterceptorTargetPtr<U>& aTarget)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
RefPtr<T> newRef(static_cast<T*>(aTarget.get()));
|
||||
return ToSTAUniquePtr(Move(newRef));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline MTAUniquePtr<T>
|
||||
ToMTAUniquePtr(RefPtr<T>&& aRefPtr)
|
||||
@ -171,6 +188,14 @@ ToMTAUniquePtr(RefPtr<T>&& aRefPtr)
|
||||
return MTAUniquePtr<T>(aRefPtr.forget().take());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline MTAUniquePtr<T>
|
||||
ToMTAUniquePtr(const RefPtr<T>& aRefPtr)
|
||||
{
|
||||
MOZ_ASSERT(IsCurrentThreadMTA());
|
||||
return MTAUniquePtr<T>(do_AddRef(aRefPtr).take());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline MTAUniquePtr<T>
|
||||
ToMTAUniquePtr(T* aRawPtr)
|
||||
@ -189,6 +214,17 @@ ToProxyUniquePtr(RefPtr<T>&& aRefPtr)
|
||||
return ProxyUniquePtr<T>(aRefPtr.forget().take());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline ProxyUniquePtr<T>
|
||||
ToProxyUniquePtr(const RefPtr<T>& aRefPtr)
|
||||
{
|
||||
MOZ_ASSERT(IsProxy(aRawPtr));
|
||||
MOZ_ASSERT((XRE_IsParentProcess() && NS_IsMainThread()) ||
|
||||
(XRE_IsContentProcess() && IsCurrentThreadMTA()));
|
||||
|
||||
return ProxyUniquePtr<T>(do_AddRef(aRefPtr).take());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline ProxyUniquePtr<T>
|
||||
ToProxyUniquePtr(T* aRawPtr)
|
||||
@ -203,6 +239,13 @@ ToProxyUniquePtr(T* aRawPtr)
|
||||
return ProxyUniquePtr<T>(aRawPtr);
|
||||
}
|
||||
|
||||
template <typename T, typename Deleter>
|
||||
inline InterceptorTargetPtr<T>
|
||||
ToInterceptorTargetPtr(const UniquePtr<T, Deleter>& aTargetPtr)
|
||||
{
|
||||
return InterceptorTargetPtr<T>(aTargetPtr.get());
|
||||
}
|
||||
|
||||
template <typename T, typename Deleter>
|
||||
inline detail::UniquePtrGetterAddRefs<T, Deleter>
|
||||
getter_AddRefs(UniquePtr<T, Deleter>& aSmartPtr)
|
||||
|
@ -33,7 +33,7 @@ if CONFIG['ACCESSIBILITY']:
|
||||
EXPORTS.mozilla.mscom += [
|
||||
'ActivationContext.h',
|
||||
'DispatchForwarder.h',
|
||||
'IHandlerPayload.h',
|
||||
'IHandlerProvider.h',
|
||||
'Interceptor.h',
|
||||
'InterceptorLog.h',
|
||||
'MainThreadHandoff.h',
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "Module.h"
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "nsWindowsHelpers.h"
|
||||
|
||||
#include <objbase.h>
|
||||
@ -21,27 +22,29 @@
|
||||
namespace mozilla {
|
||||
namespace mscom {
|
||||
|
||||
Handler::Handler(IUnknown* aOuter, HRESULT& aResult)
|
||||
Handler::Handler(IUnknown* aOuter, HRESULT* aResult)
|
||||
: mRefCnt(0)
|
||||
, mOuter(aOuter)
|
||||
, mUnmarshal(nullptr)
|
||||
, mHasPayload(false)
|
||||
{
|
||||
MOZ_ASSERT(aResult);
|
||||
|
||||
if (!aOuter) {
|
||||
aResult = E_INVALIDARG;
|
||||
*aResult = E_INVALIDARG;
|
||||
return;
|
||||
}
|
||||
|
||||
StabilizedRefCount<ULONG> stabilizer(mRefCnt);
|
||||
|
||||
aResult = ::CoGetStdMarshalEx(aOuter, SMEXF_HANDLER,
|
||||
getter_AddRefs(mInnerUnk));
|
||||
if (FAILED(aResult)) {
|
||||
*aResult = ::CoGetStdMarshalEx(aOuter, SMEXF_HANDLER,
|
||||
getter_AddRefs(mInnerUnk));
|
||||
if (FAILED(*aResult)) {
|
||||
return;
|
||||
}
|
||||
|
||||
aResult = mInnerUnk->QueryInterface(IID_IMarshal, (void**)&mUnmarshal);
|
||||
if (FAILED(aResult)) {
|
||||
*aResult = mInnerUnk->QueryInterface(IID_IMarshal, (void**)&mUnmarshal);
|
||||
if (FAILED(*aResult)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -90,11 +93,12 @@ Handler::InternalAddRef()
|
||||
ULONG
|
||||
Handler::InternalRelease()
|
||||
{
|
||||
if (--mRefCnt == 0) {
|
||||
ULONG newRefCnt = --mRefCnt;
|
||||
if (newRefCnt == 0) {
|
||||
delete this;
|
||||
Module::Unlock();
|
||||
}
|
||||
return mRefCnt;
|
||||
return newRefCnt;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
|
@ -106,7 +106,7 @@ public:
|
||||
static HRESULT Unregister(REFCLSID aClsid);
|
||||
|
||||
protected:
|
||||
Handler(IUnknown* aOuter, HRESULT& aResult);
|
||||
Handler(IUnknown* aOuter, HRESULT* aResult);
|
||||
virtual ~Handler() {}
|
||||
bool HasPayload() const { return mHasPayload; }
|
||||
IUnknown* GetOuter() const { return mOuter; }
|
||||
|
@ -38,6 +38,8 @@ parser = argparse.ArgumentParser(
|
||||
description='Run a spidermonkey shell build job')
|
||||
parser.add_argument('--dep', action='store_true',
|
||||
help='do not clobber the objdir before building')
|
||||
parser.add_argument('--keep', action='store_true',
|
||||
help='do not delete the sanitizer output directory (for testing)')
|
||||
parser.add_argument('--platform', '-p', type=str, metavar='PLATFORM',
|
||||
default='', help='build platform, including a suffix ("-debug" or "") used by buildbot to override the variant\'s "debug" setting. The platform can be used to specify 32 vs 64 bits.')
|
||||
parser.add_argument('--timeout', '-t', type=int, metavar='TIMEOUT',
|
||||
@ -275,7 +277,7 @@ timer.daemon = True
|
||||
timer.start()
|
||||
|
||||
ensure_dir_exists(OBJDIR, clobber=not args.dep and not args.nobuild)
|
||||
ensure_dir_exists(OUTDIR)
|
||||
ensure_dir_exists(OUTDIR, clobber=not args.keep)
|
||||
|
||||
|
||||
def run_command(command, check=False, **kwargs):
|
||||
@ -373,6 +375,8 @@ test_suites |= set(normalize_tests(variant.get('extra-tests', {}).get('all', [])
|
||||
# Now adjust the variant's default test list with command-line arguments.
|
||||
test_suites |= set(normalize_tests(args.run_tests.split(",")))
|
||||
test_suites -= set(normalize_tests(args.skip_tests.split(",")))
|
||||
if 'all' in args.skip_tests.split(","):
|
||||
test_suites = []
|
||||
|
||||
# Always run all enabled tests, even if earlier ones failed. But return the
|
||||
# first failed status.
|
||||
@ -408,6 +412,7 @@ if args.variant in ('tsan', 'msan'):
|
||||
|
||||
# Summarize results
|
||||
sites = Counter()
|
||||
errors = Counter()
|
||||
for filename in fullfiles:
|
||||
with open(os.path.join(OUTDIR, filename), 'rb') as fh:
|
||||
for line in fh:
|
||||
@ -427,11 +432,48 @@ if args.variant in ('tsan', 'msan'):
|
||||
print >> outfh, "%d %s" % (count, location)
|
||||
print(open(summary_filename, 'rb').read())
|
||||
|
||||
max_allowed = None
|
||||
if 'max-errors' in variant:
|
||||
print("Found %d errors out of %d allowed" % (len(sites), variant['max-errors']))
|
||||
if len(sites) > variant['max-errors']:
|
||||
max_allowed = variant['max-errors']
|
||||
elif 'expect-errors' in variant:
|
||||
max_allowed = len(variant['expect-errors'])
|
||||
|
||||
if max_allowed is not None:
|
||||
print("Found %d errors out of %d allowed" % (len(sites), max_allowed))
|
||||
if len(sites) > max_allowed:
|
||||
results.append(1)
|
||||
|
||||
if 'expect-errors' in variant:
|
||||
# Line numbers may shift around between versions, so just look for
|
||||
# matching filenames and function names. This will still produce false
|
||||
# positives when functions are renamed or moved between files, or
|
||||
# things change so that the actual race is in a different place. But it
|
||||
# still seems preferable to saying "You introduced an additional race.
|
||||
# Here are the 21 races detected; please ignore the 20 known ones in
|
||||
# this other list."
|
||||
|
||||
for site in sites:
|
||||
# Grab out the file and function names.
|
||||
m = re.search(r'/([^/]+):\d+ in (.+)', site)
|
||||
if m:
|
||||
error = tuple(m.groups())
|
||||
else:
|
||||
# will get here if eg tsan symbolication fails
|
||||
error = (site, '(unknown)')
|
||||
errors[error] += 1
|
||||
|
||||
remaining = Counter(errors)
|
||||
for expect in variant['expect-errors']:
|
||||
# expect-errors is an array of (filename, function) tuples.
|
||||
expect = tuple(expect)
|
||||
if remaining[expect] == 0:
|
||||
print("Did not see expected error in %s function %s" % expect)
|
||||
else:
|
||||
remaining[expect] -= 1
|
||||
|
||||
for filename, function in (e for e, c in remaining.items() if c > 0):
|
||||
print("*** tsan error in %s function %s" % (filename, function))
|
||||
|
||||
# Gather individual results into a tarball. Note that these are
|
||||
# distinguished only by pid of the JS process running within each test, so
|
||||
# given the 16-bit limitation of pids, it's totally possible that some of
|
||||
|
@ -7,7 +7,29 @@
|
||||
"LLVM_SYMBOLIZER": "{TOOLTOOL_CHECKOUT}/clang/bin/llvm-symbolizer",
|
||||
"JITTEST_EXTRA_ARGS": "--jitflags=debug --ignore-timeouts={DIR}/cgc-jittest-timeouts.txt",
|
||||
"JSTESTS_EXTRA_ARGS": "--exclude-file={DIR}/cgc-jstests-slow.txt",
|
||||
"TSAN_OPTIONS": "log_path={OUTDIR}/sanitize_log"
|
||||
"TSAN_OPTIONS": "exitcode=0 log_path={OUTDIR}/sanitize_log"
|
||||
},
|
||||
"max-errors": 14
|
||||
"[comment on expect-errors]": "Note that expect-errors may contain duplicates. These indicate that tsan reports errors as two distinct line numbers. We cannot just insert line numbers, because they will shift around between versions.",
|
||||
"expect-errors": [
|
||||
[ "Shape.h", "inDictionary" ],
|
||||
[ "jsfriendapi.h", "GetObjectClass" ],
|
||||
[ "Shape.h", "maybeSlot" ],
|
||||
[ "Barrier.h", "set" ],
|
||||
[ "jitprofiling.c", "iJIT_GetNewMethodID" ],
|
||||
[ "Statistics.h", "count" ],
|
||||
[ "Shape.h", "setOverwritten" ],
|
||||
[ "TestingFunctions.cpp", "js::DefineTestingFunctions(JSContext*, JS::Handle<JSObject*>, bool, bool)" ],
|
||||
[ "TestingFunctions.cpp", "js::DefineTestingFunctions(JSContext*, JS::Handle<JSObject*>, bool, bool)" ],
|
||||
[ "OSObject.cpp", "js::shell::DefineOS(JSContext*, JS::Handle<JSObject*>, bool, js::shell::RCFile**, js::shell::RCFile**)" ],
|
||||
[ "OSObject.cpp", "js::shell::DefineOS(JSContext*, JS::Handle<JSObject*>, bool, js::shell::RCFile**, js::shell::RCFile**)" ],
|
||||
[ "ObjectGroup.h", "addendumKind" ],
|
||||
[ "jsfriendapi.h", "numFixedSlots" ],
|
||||
[ "Marking.cpp", "js::GCMarker::reset()" ],
|
||||
[ "jsfun.h", "setResolvedLength" ],
|
||||
[ "Shape.h", "incrementNumLinearSearches" ],
|
||||
[ "Statistics.h", "js::gc::GCRuntime::pickChunk(js::AutoLockGC const&, js::gc::AutoMaybeStartBackgroundAllocation&)" ],
|
||||
[ "jsfun.h", "needsSomeEnvironmentObject" ],
|
||||
[ "TypeInference-inl.h", "setBasePropertyCount" ],
|
||||
[ "Statistics.h", "js::gc::GCRuntime::getOrAllocChunk(js::AutoLockGC const&, js::gc::AutoMaybeStartBackgroundAllocation&)" ]
|
||||
]
|
||||
}
|
||||
|
63
js/src/jit-test/tests/ion/recover-newarrayiterator.js
Normal file
63
js/src/jit-test/tests/ion/recover-newarrayiterator.js
Normal file
@ -0,0 +1,63 @@
|
||||
var max = 40;
|
||||
setJitCompilerOption("ion.warmup.trigger", max - 10);
|
||||
|
||||
function selfhosted() {
|
||||
if (typeof getSelfHostedValue === "undefined")
|
||||
return;
|
||||
|
||||
var NewArrayIterator = getSelfHostedValue("NewArrayIterator");
|
||||
var iter = NewArrayIterator();
|
||||
bailout();
|
||||
// assertRecoveredOnBailout(iter, true);
|
||||
}
|
||||
|
||||
function iterator(i) {
|
||||
var array = [1, i];
|
||||
var iter = array[Symbol.iterator]();
|
||||
assertEq(iter.next().value, 1);
|
||||
bailout();
|
||||
// This sometimes fails
|
||||
// assertRecoveredOnBailout(iter, true);
|
||||
var result = iter.next();
|
||||
assertEq(result.value, i);
|
||||
assertEq(result.done, false);
|
||||
assertEq(iter.next().done, true);
|
||||
}
|
||||
|
||||
function forof(i) {
|
||||
var array = [1, i];
|
||||
var first = true;
|
||||
|
||||
for (var x of array) {
|
||||
if (first) {
|
||||
assertEq(x, 1);
|
||||
bailout();
|
||||
first = false;
|
||||
} else {
|
||||
assertEq(x, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var data = {
|
||||
a: 'foo',
|
||||
b: {c: 'd'},
|
||||
arr: [1, 2, 3]
|
||||
};
|
||||
|
||||
function fn() {
|
||||
var {a, b:{c:b}, arr:[, c]} = data;
|
||||
return c;
|
||||
}
|
||||
|
||||
function destructuring() {
|
||||
for (var i = 0; i < max; i++)
|
||||
assertEq(fn(), 2);
|
||||
}
|
||||
|
||||
for (var i = 0; i < max; i++) {
|
||||
selfhosted();
|
||||
iterator(i);
|
||||
forof(i);
|
||||
destructuring();
|
||||
}
|
@ -12,8 +12,6 @@
|
||||
#include "mozilla/SizePrintfMacros.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "jsprf.h"
|
||||
|
||||
#include "gc/Marking.h"
|
||||
@ -645,14 +643,14 @@ JitcodeGlobalTable::generateTowerHeight()
|
||||
rand_ ^= mozilla::RotateLeft(rand_, 5) ^ mozilla::RotateLeft(rand_, 24);
|
||||
rand_ += 0x37798849;
|
||||
|
||||
// Return number of lowbit zeros in new randval.
|
||||
// Return 1 + number of lowbit zeros in new randval, capped at MAX_HEIGHT.
|
||||
unsigned result = 0;
|
||||
for (unsigned i = 0; i < 32; i++) {
|
||||
for (unsigned i = 0; i < JitcodeSkiplistTower::MAX_HEIGHT - 1; i++) {
|
||||
if ((rand_ >> i) & 0x1)
|
||||
break;
|
||||
result++;
|
||||
}
|
||||
return (std::max)(1U, result);
|
||||
return result + 1;
|
||||
}
|
||||
|
||||
JitcodeSkiplistTower*
|
||||
|
@ -4932,10 +4932,12 @@ MObjectState::templateObjectOf(MDefinition* obj)
|
||||
return obj->toNewObject()->templateObject();
|
||||
else if (obj->isCreateThisWithTemplate())
|
||||
return obj->toCreateThisWithTemplate()->templateObject();
|
||||
else
|
||||
else if (obj->isNewCallObject())
|
||||
return obj->toNewCallObject()->templateObject();
|
||||
else if (obj->isNewArrayIterator())
|
||||
return obj->toNewArrayIterator()->templateObject();
|
||||
|
||||
return nullptr;
|
||||
MOZ_CRASH("unreachable");
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -3556,6 +3556,11 @@ class MNewArrayIterator
|
||||
AliasSet getAliasSet() const override {
|
||||
return AliasSet::None();
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
|
||||
bool canRecoverOnBailout() const override {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jsiter.h"
|
||||
#include "jsmath.h"
|
||||
#include "jsobj.h"
|
||||
#include "jsstr.h"
|
||||
@ -1365,6 +1366,34 @@ RNewArray::recover(JSContext* cx, SnapshotIterator& iter) const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MNewArrayIterator::writeRecoverData(CompactBufferWriter& writer) const
|
||||
{
|
||||
MOZ_ASSERT(canRecoverOnBailout());
|
||||
writer.writeUnsigned(uint32_t(RInstruction::Recover_NewArrayIterator));
|
||||
return true;
|
||||
}
|
||||
|
||||
RNewArrayIterator::RNewArrayIterator(CompactBufferReader& reader)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
RNewArrayIterator::recover(JSContext* cx, SnapshotIterator& iter) const
|
||||
{
|
||||
RootedObject templateObject(cx, &iter.read().toObject());
|
||||
RootedValue result(cx);
|
||||
|
||||
|
||||
JSObject* resultObject = NewArrayIteratorObject(cx);
|
||||
if (!resultObject)
|
||||
return false;
|
||||
|
||||
result.setObject(*resultObject);
|
||||
iter.storeInstructionResult(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MNewDerivedTypedObject::writeRecoverData(CompactBufferWriter& writer) const
|
||||
{
|
||||
|
@ -102,6 +102,7 @@ namespace jit {
|
||||
_(NewObject) \
|
||||
_(NewTypedArray) \
|
||||
_(NewArray) \
|
||||
_(NewArrayIterator) \
|
||||
_(NewDerivedTypedObject) \
|
||||
_(CreateThisWithTemplate) \
|
||||
_(Lambda) \
|
||||
@ -593,6 +594,14 @@ class RNewArray final : public RInstruction
|
||||
MOZ_MUST_USE bool recover(JSContext* cx, SnapshotIterator& iter) const override;
|
||||
};
|
||||
|
||||
class RNewArrayIterator final : public RInstruction
|
||||
{
|
||||
public:
|
||||
RINSTRUCTION_HEADER_NUM_OP_(NewArrayIterator, 1)
|
||||
|
||||
MOZ_MUST_USE bool recover(JSContext* cx, SnapshotIterator& iter) const override;
|
||||
};
|
||||
|
||||
class RNewDerivedTypedObject final : public RInstruction
|
||||
{
|
||||
public:
|
||||
|
@ -134,6 +134,13 @@ IsLambdaEscaped(MLambda* lambda, JSObject* obj)
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsOptimizableObjectInstruction(MInstruction* ins)
|
||||
{
|
||||
return ins->isNewObject() || ins->isCreateThisWithTemplate() || ins->isNewCallObject() ||
|
||||
ins->isNewArrayIterator();
|
||||
}
|
||||
|
||||
// Returns False if the object is not escaped and if it is optimizable by
|
||||
// ScalarReplacementOfObject.
|
||||
//
|
||||
@ -143,8 +150,8 @@ static bool
|
||||
IsObjectEscaped(MInstruction* ins, JSObject* objDefault)
|
||||
{
|
||||
MOZ_ASSERT(ins->type() == MIRType::Object);
|
||||
MOZ_ASSERT(ins->isNewObject() || ins->isGuardShape() || ins->isCreateThisWithTemplate() ||
|
||||
ins->isNewCallObject() || ins->isFunctionEnvironment());
|
||||
MOZ_ASSERT(IsOptimizableObjectInstruction(ins) || ins->isGuardShape() ||
|
||||
ins->isFunctionEnvironment());
|
||||
|
||||
JitSpewDef(JitSpew_Escape, "Check object\n", ins);
|
||||
JitSpewIndent spewIndent(JitSpew_Escape);
|
||||
@ -1311,8 +1318,7 @@ ScalarReplacement(MIRGenerator* mir, MIRGraph& graph)
|
||||
return false;
|
||||
|
||||
for (MInstructionIterator ins = block->begin(); ins != block->end(); ins++) {
|
||||
if ((ins->isNewObject() || ins->isCreateThisWithTemplate() || ins->isNewCallObject()) &&
|
||||
!IsObjectEscaped(*ins))
|
||||
if (IsOptimizableObjectInstruction(*ins) && !IsObjectEscaped(*ins))
|
||||
{
|
||||
ObjectMemoryView view(graph.alloc(), *ins);
|
||||
if (!replaceObject.run(view))
|
||||
|
@ -4511,10 +4511,10 @@ JSCompartment::findDeadProxyZoneEdges(bool* foundAny)
|
||||
if (IsDeadProxyObject(&value.toObject())) {
|
||||
*foundAny = true;
|
||||
CrossCompartmentKey& key = e.front().mutableKey();
|
||||
Zone* wrapperZone = key.as<JSObject*>()->zone();
|
||||
if (!wrapperZone->isGCMarking())
|
||||
Zone* wrappedZone = key.as<JSObject*>()->zone();
|
||||
if (!wrappedZone->isGCMarking())
|
||||
continue;
|
||||
if (!wrapperZone->gcSweepGroupEdges().put(zone()))
|
||||
if (!wrappedZone->gcSweepGroupEdges().put(zone()))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1947,8 +1947,12 @@ Debugger::slowPathOnNewScript(JSContext* cx, HandleScript script)
|
||||
return JSTRAP_CONTINUE;
|
||||
});
|
||||
|
||||
if (status == JSTRAP_ERROR)
|
||||
// dispatchHook may fail due to OOM. This OOM is not handlable at the
|
||||
// callsites of onNewScript in the engine.
|
||||
if (status == JSTRAP_ERROR) {
|
||||
cx->clearPendingException();
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(status == JSTRAP_CONTINUE);
|
||||
}
|
||||
@ -1967,8 +1971,12 @@ Debugger::slowPathOnNewWasmInstance(JSContext* cx, Handle<WasmInstanceObject*> w
|
||||
return JSTRAP_CONTINUE;
|
||||
});
|
||||
|
||||
if (status == JSTRAP_ERROR)
|
||||
// dispatchHook may fail due to OOM. This OOM is not handlable at the
|
||||
// callsites of onNewWasmInstance in the engine.
|
||||
if (status == JSTRAP_ERROR) {
|
||||
cx->clearPendingException();
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(status == JSTRAP_CONTINUE);
|
||||
}
|
||||
|
@ -148,7 +148,7 @@ public:
|
||||
uint32_t((TimeStamp::Now() - start).ToMilliseconds()));
|
||||
if (hadSnowWhiteObjects && !mContinuation) {
|
||||
mContinuation = true;
|
||||
if (NS_FAILED(NS_DispatchToCurrentThread(this))) {
|
||||
if (NS_FAILED(Dispatch())) {
|
||||
mActive = false;
|
||||
}
|
||||
} else {
|
||||
@ -169,13 +169,25 @@ public:
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void Dispatch(bool aContinuation = false, bool aPurge = false)
|
||||
nsresult Dispatch()
|
||||
{
|
||||
if (NS_IsMainThread()) {
|
||||
nsCOMPtr<nsIRunnable> self(this);
|
||||
return SystemGroup::Dispatch("AsyncFreeSnowWhite",
|
||||
TaskCategory::GarbageCollection,
|
||||
self.forget());
|
||||
} else {
|
||||
return NS_DispatchToCurrentThread(this);
|
||||
}
|
||||
}
|
||||
|
||||
void Start(bool aContinuation = false, bool aPurge = false)
|
||||
{
|
||||
if (mContinuation) {
|
||||
mContinuation = aContinuation;
|
||||
}
|
||||
mPurge = aPurge;
|
||||
if (!mActive && NS_SUCCEEDED(NS_DispatchToCurrentThread(this))) {
|
||||
if (!mActive && NS_SUCCEEDED(Dispatch())) {
|
||||
mActive = true;
|
||||
}
|
||||
}
|
||||
@ -735,7 +747,7 @@ XPCJSContext::EndCycleCollectionCallback(CycleCollectorResults& aResults)
|
||||
void
|
||||
XPCJSContext::DispatchDeferredDeletion(bool aContinuation, bool aPurge)
|
||||
{
|
||||
mAsyncSnowWhiteFreer->Dispatch(aContinuation, aPurge);
|
||||
mAsyncSnowWhiteFreer->Start(aContinuation, aPurge);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -97,6 +97,7 @@ XPCWrappedNativeScope::XPCWrappedNativeScope(JSContext* cx,
|
||||
mNext(nullptr),
|
||||
mGlobalJSObject(aGlobal),
|
||||
mHasCallInterpositions(false),
|
||||
mDocGroupValidation(false),
|
||||
mIsContentXBLScope(false),
|
||||
mIsAddonScope(false)
|
||||
{
|
||||
@ -167,6 +168,9 @@ XPCWrappedNativeScope::XPCWrappedNativeScope(JSContext* cx,
|
||||
if (addonId) {
|
||||
// We forbid CPOWs unless they're specifically allowed.
|
||||
priv->allowCPOWs = gAllowCPOWAddonSet ? gAllowCPOWAddonSet->has(addonId) : false;
|
||||
|
||||
// Automatically opt into DocGroup validation for add-on compartments.
|
||||
mDocGroupValidation = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1373,6 +1373,12 @@ AllowCPOWsInAddon(const nsACString& addonIdStr, bool allow)
|
||||
return XPCWrappedNativeScope::AllowCPOWsInAddon(jsapi.cx(), addonId, allow);
|
||||
}
|
||||
|
||||
void
|
||||
SetDocGroupValidation(JSObject* global)
|
||||
{
|
||||
CompartmentPrivate::Get(global)->scope->SetDocGroupValidation();
|
||||
}
|
||||
|
||||
} // namespace xpc
|
||||
|
||||
namespace mozilla {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user