merge mozilla-central to autoland. r=merge a=merge on a CLOSED TREE

--HG--
extra : amend_source : 5afba38563fd825a1d36aaee0debd5844aca3432
This commit is contained in:
Sebastian Hengst 2017-10-27 12:54:29 +03:00
Родитель 63671755de 5c15da1f08
Коммит a92de1bfc3
261 изменённых файлов: 7630 добавлений и 5160 удалений

Просмотреть файл

@ -128,7 +128,8 @@ HandlerProvider::GetAndSerializePayload(const MutexAutoLock&)
}
HRESULT
HandlerProvider::GetHandlerPayloadSize(NotNull<DWORD*> aOutPayloadSize)
HandlerProvider::GetHandlerPayloadSize(NotNull<mscom::IInterceptor*> aInterceptor,
NotNull<DWORD*> aOutPayloadSize)
{
MOZ_ASSERT(mscom::IsCurrentThreadMTA());
@ -151,6 +152,33 @@ HandlerProvider::GetHandlerPayloadSize(NotNull<DWORD*> aOutPayloadSize)
return S_OK;
}
template <typename CondFnT, typename ExeFnT>
class MOZ_RAII ExecuteWhen final
{
public:
ExecuteWhen(CondFnT& aCondFn, ExeFnT& aExeFn)
: mCondFn(aCondFn)
, mExeFn(aExeFn)
{
}
~ExecuteWhen()
{
if (mCondFn()) {
mExeFn();
}
}
ExecuteWhen(const ExecuteWhen&) = delete;
ExecuteWhen(ExecuteWhen&&) = delete;
ExecuteWhen& operator=(const ExecuteWhen&) = delete;
ExecuteWhen& operator=(ExecuteWhen&&) = delete;
private:
CondFnT& mCondFn;
ExeFnT& mExeFn;
};
void
HandlerProvider::BuildIA2Data(IA2Data* aOutIA2Data)
{
@ -162,18 +190,104 @@ HandlerProvider::BuildIA2Data(IA2Data* aOutIA2Data)
RefPtr<NEWEST_IA2_INTERFACE>
target(static_cast<NEWEST_IA2_INTERFACE*>(mTargetUnk.get()));
HRESULT hr = E_UNEXPECTED;
auto hasFailed = [&hr]() -> bool {
return FAILED(hr);
};
auto cleanup = [this, aOutIA2Data]() -> void {
ClearIA2Data(*aOutIA2Data);
};
ExecuteWhen<decltype(hasFailed), decltype(cleanup)> onFail(hasFailed, cleanup);
const VARIANT kChildIdSelf = {VT_I4};
VARIANT varVal;
hr = target->accLocation(&aOutIA2Data->mLeft, &aOutIA2Data->mTop,
&aOutIA2Data->mWidth, &aOutIA2Data->mHeight,
kChildIdSelf);
if (FAILED(hr)) {
return;
}
hr = target->get_accRole(kChildIdSelf, &aOutIA2Data->mRole);
if (FAILED(hr)) {
return;
}
hr = target->get_accState(kChildIdSelf, &varVal);
if (FAILED(hr)) {
return;
}
aOutIA2Data->mState = varVal.lVal;
hr = target->get_accKeyboardShortcut(kChildIdSelf,
&aOutIA2Data->mKeyboardShortcut);
if (FAILED(hr)) {
return;
}
hr = target->get_accName(kChildIdSelf, &aOutIA2Data->mName);
if (FAILED(hr)) {
return;
}
hr = target->get_accDescription(kChildIdSelf, &aOutIA2Data->mDescription);
if (FAILED(hr)) {
return;
}
hr = target->get_accChildCount(&aOutIA2Data->mChildCount);
if (FAILED(hr)) {
return;
}
hr = target->get_accValue(kChildIdSelf, &aOutIA2Data->mValue);
if (FAILED(hr)) {
return;
}
hr = target->get_states(&aOutIA2Data->mIA2States);
if (FAILED(hr)) {
return;
}
hr = target->get_attributes(&aOutIA2Data->mAttributes);
if (FAILED(hr)) {
return;
}
HWND hwnd;
hr = target->get_windowHandle(&hwnd);
if (FAILED(hr)) {
return;
}
aOutIA2Data->mHwnd = PtrToLong(hwnd);
hr = target->get_locale(&aOutIA2Data->mIA2Locale);
if (FAILED(hr)) {
return;
}
hr = target->role(&aOutIA2Data->mIA2Role);
if (FAILED(hr)) {
return;
}
// 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);
}
hr = target->get_uniqueID(&aOutIA2Data->mUniqueId);
}
void
HandlerProvider::ClearIA2Data(IA2Data& aData)
{
::VariantClear(&aData.mRole);
ZeroMemory(&aData, sizeof(IA2Data));
}
@ -184,7 +298,8 @@ HandlerProvider::IsTargetInterfaceCacheable()
}
HRESULT
HandlerProvider::WriteHandlerPayload(NotNull<IStream*> aStream)
HandlerProvider::WriteHandlerPayload(NotNull<mscom::IInterceptor*> aInterceptor,
NotNull<IStream*> aStream)
{
MutexAutoLock lock(mMutex);

Просмотреть файл

@ -41,8 +41,10 @@ public:
// IHandlerProvider
STDMETHODIMP GetHandler(NotNull<CLSID*> aHandlerClsid) override;
STDMETHODIMP GetHandlerPayloadSize(NotNull<DWORD*> aOutPayloadSize) override;
STDMETHODIMP WriteHandlerPayload(NotNull<IStream*> aStream) override;
STDMETHODIMP GetHandlerPayloadSize(NotNull<mscom::IInterceptor*> aInterceptor,
NotNull<DWORD*> aOutPayloadSize) override;
STDMETHODIMP WriteHandlerPayload(NotNull<mscom::IInterceptor*> aInterceptor,
NotNull<IStream*> aStream) override;
STDMETHODIMP_(REFIID) MarshalAs(REFIID aIid) override;
STDMETHODIMP_(REFIID) GetEffectiveOutParamIid(REFIID aCallIid,
ULONG aCallMethod) override;

Просмотреть файл

@ -49,7 +49,8 @@ static const mozilla::mscom::ArrayData sPlatformChildArrayData[] = {
// we intend to instantiate them. Therefore RegisterProxy() must be called
// via EnsureMTA.
PlatformChild::PlatformChild()
: mAccTypelib(mozilla::mscom::RegisterTypelib(L"oleacc.dll",
: mIA2Proxy(mozilla::mscom::RegisterProxy(L"ia2marshal.dll"))
, mAccTypelib(mozilla::mscom::RegisterTypelib(L"oleacc.dll",
mozilla::mscom::RegistrationFlags::eUseSystemDirectory))
, mMiscTypelib(mozilla::mscom::RegisterTypelib(L"Accessible.tlb"))
, mSdnTypelib(mozilla::mscom::RegisterTypelib(L"AccessibleMarshal.dll"))
@ -72,11 +73,12 @@ PlatformChild::PlatformChild()
});
mCustomProxy = Move(customProxy);
UniquePtr<mozilla::mscom::RegisteredProxy> ia2Proxy;
mozilla::mscom::EnsureMTA([&ia2Proxy]() -> void {
ia2Proxy = Move(mozilla::mscom::RegisterProxy(L"ia2marshal.dll"));
// IA2 needs to be registered in both the main thread's STA as well as the MTA
UniquePtr<mozilla::mscom::RegisteredProxy> ia2ProxyMTA;
mozilla::mscom::EnsureMTA([&ia2ProxyMTA]() -> void {
ia2ProxyMTA = Move(mozilla::mscom::RegisterProxy(L"ia2marshal.dll"));
});
mIA2Proxy = Move(ia2Proxy);
mIA2ProxyMTA = Move(ia2ProxyMTA);
}
} // namespace a11y

Просмотреть файл

@ -28,6 +28,7 @@ private:
mscom::MTADeletePtr<mozilla::mscom::ActivationContextRegion> mActCtxMTA;
UniquePtr<mozilla::mscom::RegisteredProxy> mCustomProxy;
UniquePtr<mozilla::mscom::RegisteredProxy> mIA2Proxy;
UniquePtr<mozilla::mscom::RegisteredProxy> mIA2ProxyMTA;
UniquePtr<mozilla::mscom::RegisteredProxy> mAccTypelib;
UniquePtr<mozilla::mscom::RegisteredProxy> mMiscTypelib;
UniquePtr<mozilla::mscom::RegisteredProxy> mSdnTypelib;

Просмотреть файл

@ -368,6 +368,12 @@ AccessibleHandler::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,
pVarResult, pExcepInfo, puArgErr);
}
inline static BSTR
CopyBSTR(BSTR aSrc)
{
return ::SysAllocStringLen(aSrc, ::SysStringLen(aSrc));
}
#define BEGIN_CACHE_ACCESS \
{ \
HRESULT hr; \
@ -376,11 +382,15 @@ AccessibleHandler::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,
} \
}
static BSTR
CopyBSTR(BSTR aSrc)
{
return SysAllocStringLen(aSrc, SysStringLen(aSrc));
}
#define GET_FIELD(member, assignTo) \
{ \
assignTo = mCachedData.mData.member; \
}
#define GET_BSTR(member, assignTo) \
{ \
assignTo = CopyBSTR(mCachedData.mData.member); \
}
HRESULT
AccessibleHandler::get_accParent(IDispatch **ppdispParent)
@ -398,11 +408,18 @@ AccessibleHandler::get_accChildCount(long *pcountChildren)
if (!pcountChildren) {
return E_INVALIDARG;
}
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
if (!HasPayload()) {
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
}
return mIA2PassThru->get_accChildCount(pcountChildren);
}
return mIA2PassThru->get_accChildCount(pcountChildren);
BEGIN_CACHE_ACCESS;
GET_FIELD(mChildCount, *pcountChildren);
return S_OK;
}
HRESULT
@ -430,11 +447,18 @@ AccessibleHandler::get_accName(VARIANT varChild, BSTR *pszName)
if (!pszName) {
return E_INVALIDARG;
}
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
if (varChild.lVal != CHILDID_SELF || !HasPayload()) {
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
}
return mIA2PassThru->get_accName(varChild, pszName);
}
return mIA2PassThru->get_accName(varChild, pszName);
BEGIN_CACHE_ACCESS;
GET_BSTR(mName, *pszName);
return S_OK;
}
HRESULT
@ -443,11 +467,18 @@ AccessibleHandler::get_accValue(VARIANT varChild, BSTR *pszValue)
if (!pszValue) {
return E_INVALIDARG;
}
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
if (varChild.lVal != CHILDID_SELF || !HasPayload()) {
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
}
return mIA2PassThru->get_accValue(varChild, pszValue);
}
return mIA2PassThru->get_accValue(varChild, pszValue);
BEGIN_CACHE_ACCESS;
GET_BSTR(mValue, *pszValue);
return S_OK;
}
HRESULT
@ -456,11 +487,18 @@ AccessibleHandler::get_accDescription(VARIANT varChild, BSTR *pszDescription)
if (!pszDescription) {
return E_INVALIDARG;
}
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
if (varChild.lVal != CHILDID_SELF || !HasPayload()) {
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
}
return mIA2PassThru->get_accDescription(varChild, pszDescription);
}
return mIA2PassThru->get_accDescription(varChild, pszDescription);
BEGIN_CACHE_ACCESS;
GET_BSTR(mDescription, *pszDescription);
return S_OK;
}
@ -470,11 +508,17 @@ AccessibleHandler::get_accRole(VARIANT varChild, VARIANT *pvarRole)
if (!pvarRole) {
return E_INVALIDARG;
}
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
if (varChild.lVal != CHILDID_SELF || !HasPayload()) {
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
}
return mIA2PassThru->get_accRole(varChild, pvarRole);
}
return mIA2PassThru->get_accRole(varChild, pvarRole);
BEGIN_CACHE_ACCESS;
return ::VariantCopy(pvarRole, &mCachedData.mData.mRole);
}
@ -484,11 +528,19 @@ AccessibleHandler::get_accState(VARIANT varChild, VARIANT *pvarState)
if (!pvarState) {
return E_INVALIDARG;
}
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
if (varChild.lVal != CHILDID_SELF || !HasPayload()) {
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
}
return mIA2PassThru->get_accState(varChild, pvarState);
}
return mIA2PassThru->get_accState(varChild, pvarState);
pvarState->vt = VT_I4;
BEGIN_CACHE_ACCESS;
GET_FIELD(mState, pvarState->lVal);
return S_OK;
}
HRESULT
@ -522,11 +574,18 @@ AccessibleHandler::get_accKeyboardShortcut(VARIANT varChild,
if (!pszKeyboardShortcut) {
return E_INVALIDARG;
}
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
if (varChild.lVal != CHILDID_SELF || !HasPayload()) {
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
}
return mIA2PassThru->get_accKeyboardShortcut(varChild, pszKeyboardShortcut);
}
return mIA2PassThru->get_accKeyboardShortcut(varChild, pszKeyboardShortcut);
BEGIN_CACHE_ACCESS;
GET_BSTR(mKeyboardShortcut, *pszKeyboardShortcut);
return S_OK;
}
HRESULT
@ -556,11 +615,18 @@ AccessibleHandler::get_accDefaultAction(VARIANT varChild,
if (!pszDefaultAction) {
return E_INVALIDARG;
}
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
if (varChild.lVal != CHILDID_SELF || !HasPayload()) {
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
}
return mIA2PassThru->get_accDefaultAction(varChild, pszDefaultAction);
}
return mIA2PassThru->get_accDefaultAction(varChild, pszDefaultAction);
BEGIN_CACHE_ACCESS;
GET_BSTR(mDefaultAction, *pszDefaultAction);
return S_OK;
}
HRESULT
@ -577,12 +643,25 @@ HRESULT
AccessibleHandler::accLocation(long *pxLeft, long *pyTop, long *pcxWidth,
long *pcyHeight, VARIANT varChild)
{
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
if (varChild.lVal != CHILDID_SELF || !HasPayload()) {
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
}
return mIA2PassThru->accLocation(pxLeft, pyTop, pcxWidth, pcyHeight,
varChild);
}
return mIA2PassThru->accLocation(pxLeft, pyTop, pcxWidth, pcyHeight,
varChild);
if (!pxLeft || !pyTop || !pcxWidth || !pcyHeight) {
return E_INVALIDARG;
}
BEGIN_CACHE_ACCESS;
GET_FIELD(mLeft, *pxLeft);
GET_FIELD(mTop, *pyTop);
GET_FIELD(mWidth, *pcxWidth);
GET_FIELD(mHeight, *pcyHeight);
return S_OK;
}
HRESULT
@ -669,11 +748,18 @@ AccessibleHandler::role(long* role)
if (!role) {
return E_INVALIDARG;
}
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
if (!HasPayload()) {
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
}
return mIA2PassThru->role(role);
}
return mIA2PassThru->role(role);
BEGIN_CACHE_ACCESS;
GET_FIELD(mIA2Role, *role);
return S_OK;
}
HRESULT
@ -715,11 +801,18 @@ AccessibleHandler::get_states(AccessibleStates* states)
if (!states) {
return E_INVALIDARG;
}
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
if (!HasPayload()) {
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
}
return mIA2PassThru->get_states(states);
}
return mIA2PassThru->get_states(states);
BEGIN_CACHE_ACCESS;
GET_FIELD(mIA2States, *states);
return S_OK;
}
HRESULT
@ -805,11 +898,20 @@ AccessibleHandler::get_windowHandle(HWND* windowHandle)
if (!windowHandle) {
return E_INVALIDARG;
}
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
if (!HasPayload()) {
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
}
return mIA2PassThru->get_windowHandle(windowHandle);
}
return mIA2PassThru->get_windowHandle(windowHandle);
BEGIN_CACHE_ACCESS;
long hwnd = 0;
GET_FIELD(mHwnd, hwnd);
*windowHandle = reinterpret_cast<HWND>(uintptr_t(hwnd));
return S_OK;
}
HRESULT
@ -828,11 +930,19 @@ AccessibleHandler::get_locale(IA2Locale* locale)
if (!locale) {
return E_INVALIDARG;
}
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
if (!HasPayload()) {
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
}
return mIA2PassThru->get_locale(locale);
}
return mIA2PassThru->get_locale(locale);
BEGIN_CACHE_ACCESS;
GET_BSTR(mIA2Locale.language, locale->language);
GET_BSTR(mIA2Locale.country, locale->country);
GET_BSTR(mIA2Locale.variant, locale->variant);
return S_OK;
}
@ -842,11 +952,18 @@ AccessibleHandler::get_attributes(BSTR* attributes)
if (!attributes) {
return E_INVALIDARG;
}
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
if (!HasPayload()) {
HRESULT hr = ResolveIA2();
if (FAILED(hr)) {
return hr;
}
return mIA2PassThru->get_attributes(attributes);
}
return mIA2PassThru->get_attributes(attributes);
BEGIN_CACHE_ACCESS;
GET_BSTR(mAttributes, *attributes);
return S_OK;
}
HRESULT

Просмотреть файл

@ -14,7 +14,24 @@ import "AccessibleText.idl";
typedef struct _IA2Data
{
long mUniqueId;
VARIANT mRole;
long mState;
long mChildCount;
long mIA2Role;
AccessibleStates mIA2States;
long mLeft;
long mTop;
long mWidth;
long mHeight;
long mHwnd;
BSTR mKeyboardShortcut;
BSTR mName;
BSTR mDescription;
BSTR mDefaultAction;
BSTR mValue;
BSTR mAttributes;
IA2Locale mIA2Locale;
long mUniqueId;
} IA2Data;
interface IGeckoBackChannel;

Просмотреть файл

@ -1,6 +1,5 @@
[DEFAULT]
support-files =
docload_wnd.html
focus.html
scroll.html
!/accessible/tests/mochitest/*.js
@ -19,8 +18,6 @@ support-files =
[test_coalescence.html]
[test_contextmenu.html]
[test_descrchange.html]
[test_docload.html]
[test_docload_aria.html]
[test_dragndrop.html]
[test_flush.html]
[test_focus_aria_activedescendant.html]

Просмотреть файл

@ -0,0 +1,11 @@
[DEFAULT]
support-files =
docload_wnd.html
!/accessible/tests/mochitest/*.js
[test_docload_aria.html]
[test_docload_busy.html]
[test_docload_embedded.html]
[test_docload_iframe.html]
[test_docload_root.html]
[test_docload_shutdown.html]

Просмотреть файл

@ -10,13 +10,13 @@
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="../common.js"></script>
src="../../common.js"></script>
<script type="application/javascript"
src="../role.js"></script>
src="../../role.js"></script>
<script type="application/javascript"
src="../states.js"></script>
src="../../states.js"></script>
<script type="application/javascript"
src="../events.js"></script>
src="../../events.js"></script>
<script type="application/javascript">
// //////////////////////////////////////////////////////////////////////////
@ -43,9 +43,6 @@
var gQueue = null;
// Debug stuff.
// gA11yEventDumpToConsole = true;
function doTests() {
gQueue = new eventQueue();

Просмотреть файл

@ -0,0 +1,84 @@
<html>
<head>
<title>Accessible events testing for document</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="../../common.js"></script>
<script type="application/javascript"
src="../../role.js"></script>
<script type="application/javascript"
src="../../states.js"></script>
<script type="application/javascript"
src="../../events.js"></script>
<script type="application/javascript">
// //////////////////////////////////////////////////////////////////////////
// Invokers
function makeIFrameVisible(aID) {
this.DOMNode = getNode(aID);
this.eventSeq = [
new invokerChecker(EVENT_REORDER, this.DOMNode.parentNode),
{
type: EVENT_STATE_CHANGE,
get target() {
return getAccessible("iframe").firstChild;
},
match(aEvent) {
// The document shouldn't have busy state (the DOM document was
// loaded before its accessible was created). Do this test lately to
// make sure the content of document accessible was created
// initially, prior to this the document accessible keeps busy
// state. The initial creation happens asynchronously after document
// creation, there are no events we could use to catch it.
let { state, isEnabled } = aEvent.QueryInterface(nsIAccessibleStateChangeEvent);
return state & STATE_BUSY && !isEnabled;
}
}
];
this.invoke = () => (this.DOMNode.style.visibility = "visible");
this.getID = () =>
"The accessible for DOM document loaded before it's shown shouldn't have busy state.";
}
// //////////////////////////////////////////////////////////////////////////
// Do tests
function doTests() {
const gQueue = new eventQueue();
gQueue.push(new makeIFrameVisible("iframe"));
gQueue.invoke(); // Will call SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTests);
</script>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=658185"
title="The DOM document loaded before it's shown shouldn't have busy state">
Mozilla Bug 658185
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<div id="testContainer"><iframe id="iframe" src="about:" style="visibility: hidden;"></iframe></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,86 @@
<html>
<head>
<title>Accessible events testing for document</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="../../common.js"></script>
<script type="application/javascript"
src="../../role.js"></script>
<script type="application/javascript"
src="../../events.js"></script>
<script type="application/javascript">
// //////////////////////////////////////////////////////////////////////////
// Invokers
function changeIframeSrc(aIdentifier, aURL) {
this.DOMNode = getNode(aIdentifier);
function getIframeDoc() {
return getAccessible(getNode(aIdentifier).contentDocument);
}
this.eventSeq = [
new invokerChecker(EVENT_REORDER, getAccessible(this.DOMNode)),
new asyncInvokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, getIframeDoc)
];
this.invoke = () => (this.DOMNode.src = aURL);
this.finalCheck = () =>
testAccessibleTree(this.DOMNode, {
role: ROLE_INTERNAL_FRAME,
children: [
{
role: ROLE_DOCUMENT,
name: aURL == "about:" ? "About:" : aURL
}
]
});
this.getID = () => `change iframe src on ${aURL}`;
}
// //////////////////////////////////////////////////////////////////////////
// Do tests
function doTests() {
const gQueue = new eventQueue();
gQueue.push(new changeIframeSrc("iframe", "about:"));
gQueue.push(new changeIframeSrc("iframe", "about:buildconfig"));
gQueue.invoke(); // Will call SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTests);
</script>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=420845"
title="Fire event_reorder on any embedded frames/iframes whos document has just loaded">
Mozilla Bug 420845
</a>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=754165"
title="Fire document load events on iframes too">
Mozilla Bug 754165
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<div id="testContainer"><iframe id="iframe"></iframe></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,100 @@
<html>
<head>
<title>Accessible events testing for document</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="../../common.js"></script>
<script type="application/javascript"
src="../../role.js"></script>
<script type="application/javascript"
src="../../states.js"></script>
<script type="application/javascript"
src="../../events.js"></script>
<script type="application/javascript">
// //////////////////////////////////////////////////////////////////////////
// Invokers
const kHide = 1;
const kShow = 2;
const kRemove = 3;
function morphIFrame(aIdentifier, aAction) {
this.DOMNode = getNode(aIdentifier);
this.IFrameContainerDOMNode = this.DOMNode.parentNode;
this.eventSeq = [
new invokerChecker(aAction === kShow ? EVENT_SHOW : EVENT_HIDE, this.DOMNode),
new invokerChecker(EVENT_REORDER, this.IFrameContainerDOMNode)
];
this.invoke = () => {
if (aAction === kRemove) {
this.IFrameContainerDOMNode.removeChild(this.DOMNode);
} else {
this.DOMNode.style.display = aAction === kHide ? "none" : "block";
}
};
this.finalCheck = () =>
testAccessibleTree(this.IFrameContainerDOMNode, {
role: ROLE_SECTION,
children: (aAction == kHide || aAction == kRemove) ? [ ] :
[
{
role: ROLE_INTERNAL_FRAME,
children: [
{ role: ROLE_DOCUMENT }
]
}
]
});
this.getID = () => {
if (aAction === kRemove) {
return "remove iframe";
}
return `change display style of iframe to ${aAction === kHide ? "none" : "block"}`;
};
}
// //////////////////////////////////////////////////////////////////////////
// Do tests
function doTests() {
const gQueue = new eventQueue(EVENT_REORDER);
gQueue.push(new morphIFrame("iframe", kHide));
gQueue.push(new morphIFrame("iframe", kShow));
gQueue.push(new morphIFrame("iframe", kRemove));
gQueue.invoke(); // Will call SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTests);
</script>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=566103"
title="Reorganize accessible document handling">
Mozilla Bug 566103
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<div id="testContainer"><iframe id="iframe"></iframe></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,135 @@
<html>
<head>
<title>Accessible events testing for document</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="../../common.js"></script>
<script type="application/javascript"
src="../../role.js"></script>
<script type="application/javascript">
// Front end stuff sometimes likes to stuff things in the hidden window(s)
// in which case there's accessibles for that content.
Components.utils.import("resource://gre/modules/Services.jsm");
// Force the creation of an accessible for the hidden window's document.
let doc = Services.appShell.hiddenDOMWindow.document;
gAccService.getAccessibleFor(doc);
// The private hidden window will be lazily created that's why we need to do
// it here *before* loading '../../events.js' or else we'll have a duplicate
// reorder event.
let privateDoc = Services.appShell.hiddenPrivateDOMWindow.document;
// Force the creation of an accessible for the private hidden window's doc.
gAccService.getAccessibleFor(privateDoc);
</script>
<script type="application/javascript"
src="../../events.js"></script>
<script type="application/javascript">
// //////////////////////////////////////////////////////////////////////////
// Invokers
let gDialog;
let gDialogDoc;
let gRootAcc;
function openDialogWnd(aURL) {
// Get application root accessible.
let docAcc = getAccessible(document);
while (docAcc) {
gRootAcc = docAcc;
try {
docAcc = docAcc.parent;
} catch (e) {
ok(false, `Can't get parent for ${prettyName(docAcc)}`);
throw e;
}
}
this.eventSeq = [ new invokerChecker(EVENT_REORDER, gRootAcc) ];
this.invoke = () => (gDialog = window.openDialog(aURL));
this.finalCheck = () => {
const accTree = {
role: ROLE_APP_ROOT,
children: [
{
role: ROLE_CHROME_WINDOW
},
{
role: ROLE_CHROME_WINDOW
},
{
role: ROLE_CHROME_WINDOW
},
{
role: ROLE_CHROME_WINDOW
}
]
};
testAccessibleTree(gRootAcc, accTree)
gDialogDoc = gDialog.document;
ok(isAccessibleInCache(gDialogDoc),
`The document accessible for '${aURL}' is not in cache!`);
};
this.getID = () => `open dialog '${aURL}'`;
}
function closeDialogWnd() {
this.eventSeq = [ new invokerChecker(EVENT_FOCUS, getAccessible(document)) ];
this.invoke = () => gDialog.close();
this.finalCheck = () => {
ok(!isAccessibleInCache(gDialogDoc),
`The document accessible for dialog is in cache still!`);
gDialog = gDialogDoc = gRootAcc = null;
};
this.getID = () => "close dialog";
}
// //////////////////////////////////////////////////////////////////////////
// Do tests
function doTests() {
const gQueue = new eventQueue();
gQueue.push(new openDialogWnd("about:"));
gQueue.push(new closeDialogWnd());
gQueue.invoke(); // Will call SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTests);
</script>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=506206"
title="Fire event_reorder application root accessible">
Mozilla Bug 506206
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,157 @@
<html>
<head>
<title>Accessible events testing for document</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="../../common.js"></script>
<script type="application/javascript"
src="../../role.js"></script>
<script type="application/javascript">
// Front end stuff sometimes likes to stuff things in the hidden window(s)
// in which case there's accessibles for that content.
Components.utils.import("resource://gre/modules/Services.jsm");
// Force the creation of an accessible for the hidden window's document.
let doc = Services.appShell.hiddenDOMWindow.document;
gAccService.getAccessibleFor(doc);
// The private hidden window will be lazily created that's why we need to do
// it here *before* loading '../../events.js' or else we'll have a duplicate
// reorder event.
let privateDoc = Services.appShell.hiddenPrivateDOMWindow.document;
// Force the creation of an accessible for the private hidden window's doc.
gAccService.getAccessibleFor(privateDoc);
</script>
<script type="application/javascript"
src="../../events.js"></script>
<script type="application/javascript">
// //////////////////////////////////////////////////////////////////////////
// Invokers
let gDialog;
let gDialogDoc;
let gRootAcc;
let gIframeDoc
function openWndShutdownDoc(aURL) {
// Get application root accessible.
let docAcc = getAccessible(document);
while (docAcc) {
gRootAcc = docAcc;
try {
docAcc = docAcc.parent;
} catch (e) {
ok(false, `Can't get parent for ${prettyName(docAcc)}`);
throw e;
}
}
this.eventSeq = [
new invokerChecker(EVENT_REORDER, gRootAcc),
{
type: EVENT_HIDE,
get target() {
gDialogDoc = gDialog.document;
const iframe = gDialogDoc.getElementById("iframe");
gIframeDoc = iframe.contentDocument;
return iframe;
},
get targetDescr() {
return "inner iframe of docload_wnd.html document";
}
}
];
this.invoke = () => gDialog = window.openDialog(aURL);
this.finalCheck = () => {
const accTree = {
role: ROLE_APP_ROOT,
children: [
{
role: ROLE_CHROME_WINDOW
},
{
role: ROLE_CHROME_WINDOW
},
{
role: ROLE_CHROME_WINDOW
},
{
role: ROLE_CHROME_WINDOW
}
]
};
testAccessibleTree(gRootAcc, accTree)
// After timeout after event hide for iframe was handled the document
// accessible for iframe's document should no longer be in cache.
ok(!isAccessibleInCache(gIframeDoc),
"The document accessible for iframe is in cache still after iframe hide!");
ok(isAccessibleInCache(gDialogDoc),
`The document accessible for '${aURL}' is not in cache!`);
};
this.getID = () => `open dialog '${aURL}'`;
}
function closeWndShutdownDoc() {
this.eventSeq = [ new invokerChecker(EVENT_FOCUS, getAccessible(document)) ];
this.invoke = () => gDialog.close();
this.finalCheck = () => {
ok(!isAccessibleInCache(gDialogDoc),
"The document accessible for dialog is in cache still!");
// After the window is closed all alive subdocument accessibles should
// be shut down.
ok(!isAccessibleInCache(gIframeDoc),
"The document accessible for iframe is in cache still!");
gDialog = gDialogDoc = gRootAcc = gIframeDoc = null;
};
this.getID = () => "close dialog";
}
// //////////////////////////////////////////////////////////////////////////
// Do tests
function doTests() {
const gQueue = new eventQueue();
gQueue.push(new openWndShutdownDoc("../../events/docload/docload_wnd.html"));
gQueue.push(new closeWndShutdownDoc());
gQueue.invoke(); // Will call SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTests);
</script>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=571459"
title="Shutdown document accessible when presshell goes away">
Mozilla Bug 571459
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
</body>
</html>

Просмотреть файл

@ -1,337 +0,0 @@
<html>
<head>
<title>Accessible events testing for document</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="../role.js"></script>
<script type="application/javascript"
src="../states.js"></script>
<script type="application/javascript">
// Front end stuff sometimes likes to stuff things in the hidden window(s)
// in which case there's accessibles for that content.
Components.utils.import("resource://gre/modules/Services.jsm");
// Force the creation of an accessible for the hidden window's document.
var doc = Services.appShell.hiddenDOMWindow.document;
gAccService.getAccessibleFor(doc);
// The private hidden window will be lazily created that's why we need to do
// it here *before* loading '../events.js' or else we'll have a duplicate
// reorder event.
var privateDoc = Services.appShell.hiddenPrivateDOMWindow.document;
// Force the creation of an accessible for the private hidden window's doc.
gAccService.getAccessibleFor(privateDoc);
</script>
<script type="application/javascript"
src="../events.js"></script>
<script type="application/javascript">
// //////////////////////////////////////////////////////////////////////////
// Invokers
function changeIframeSrc(aIdentifier, aURL) {
this.DOMNode = getNode(aIdentifier);
this.eventSeq = [
new invokerChecker(EVENT_REORDER, getAccessible(this.DOMNode)),
new asyncInvokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, getIframeDoc)
];
this.invoke = function changeIframeSrc_invoke() {
this.DOMNode.src = aURL;
};
this.finalCheck = function changeIframeSrc_finalCheck() {
var accTree = {
role: ROLE_INTERNAL_FRAME,
children: [
{
role: ROLE_DOCUMENT,
name: aURL == "about:" ? "About:" : aURL
}
]
};
testAccessibleTree(this.DOMNode, accTree);
};
this.getID = function changeIframeSrc_getID() {
return "change iframe src on " + aURL;
};
function getIframeDoc() {
return getAccessible(getNode(aIdentifier).contentDocument);
}
}
const kHide = 1;
const kShow = 2;
const kRemove = 3;
function morphIFrame(aIdentifier, aAction) {
this.DOMNode = getNode(aIdentifier);
this.IFrameContainerDOMNode = this.DOMNode.parentNode;
this.eventSeq = [];
var checker = null;
if (aAction == kShow)
checker = new invokerChecker(EVENT_SHOW, this.DOMNode);
else
checker = new invokerChecker(EVENT_HIDE, this.DOMNode);
this.eventSeq.push(checker);
var reorderChecker =
new invokerChecker(EVENT_REORDER, this.IFrameContainerDOMNode);
this.eventSeq.push(reorderChecker);
this.invoke = function morphIFrame_invoke() {
if (aAction == kHide) {
this.DOMNode.style.display = "none";
} else if (aAction == kShow) {
this.DOMNode.style.display = "block";
} else {
this.IFrameContainerDOMNode.removeChild(this.DOMNode);
}
};
this.finalCheck = function morphIFrame_finalCheck() {
var accTree = {
role: ROLE_SECTION,
children: (aAction == kHide || aAction == kRemove) ? [ ] :
[
{
role: ROLE_INTERNAL_FRAME,
children: [
{ role: ROLE_DOCUMENT }
]
}
]
};
testAccessibleTree(this.IFrameContainerDOMNode, accTree);
};
this.getID = function morphIFrame_getID() {
if (aAction == kRemove)
return "remove iframe";
return "change display style of iframe to " +
((aAction == kHide) ? "none" : "block");
};
}
function makeIFrameVisible(aID) {
this.DOMNode = getNode(aID);
this.eventSeq = [
new invokerChecker(EVENT_REORDER, this.DOMNode.parentNode)
];
this.invoke = function makeIFrameVisible_invoke() {
this.DOMNode.style.visibility = "visible";
};
this.getID = function makeIFrameVisible_getID() {
return "The accessible for DOM document loaded before it's shown shouldn't have busy state.";
};
}
function openDialogWnd(aURL) {
// Get application root accessible.
var docAcc = getAccessible(document);
while (docAcc) {
this.mRootAcc = docAcc;
try {
docAcc = docAcc.parent;
} catch (e) {
ok(false, "Can't get parent for " + prettyName(docAcc));
throw e;
}
}
this.eventSeq = [
new invokerChecker(EVENT_REORDER, this.mRootAcc)
];
this.invoke = function openDialogWnd_invoke() {
this.mDialog = window.openDialog(aURL);
};
this.finalCheck = function openDialogWnd_finalCheck() {
this.finalCheckImpl();
};
this.finalCheckImpl = function openDialogWnd_finalCheckImpl() {
var accTree = {
role: ROLE_APP_ROOT,
children: [
{
role: ROLE_CHROME_WINDOW
},
{
role: ROLE_CHROME_WINDOW
},
{
role: ROLE_CHROME_WINDOW
},
{
role: ROLE_CHROME_WINDOW
}
]
};
testAccessibleTree(this.mRootAcc, accTree);
var dlgDoc = this.mDialog.document;
ok(isAccessibleInCache(dlgDoc),
"The document accessible for '" + aURL + "' is not in cache!");
this.mDialog.close();
// close() is asynchronous.
SimpleTest.executeSoon(function() {
ok(!isAccessibleInCache(dlgDoc),
"The document accessible for '" + aURL + "' is in cache still!");
});
};
this.getID = function openDialogWnd_getID() {
return "open dialog '" + aURL + "'";
};
}
function openWndShutdownDoc() {
this.__proto__ =
new openDialogWnd("../events/docload_wnd.html");
var thisObj = this;
var docChecker = {
type: EVENT_HIDE,
get target() {
var iframe = this.invoker.mDialog.document.getElementById("iframe");
this.invoker.iframeDoc = iframe.contentDocument;
return iframe;
},
get targetDescr() {
return "inner iframe of docload_wnd.html document";
},
invoker: thisObj
};
this.eventSeq.push(docChecker);
this.finalCheck = function openWndShutdownDoc_finalCheck() {
// After timeout after event hide for iframe was handled the document
// accessible for iframe's document is in cache still.
ok(!isAccessibleInCache(this.iframeDoc),
"The document accessible for iframe is in cache still after iframe hide!");
this.finalCheckImpl();
// After the window is closed all alive subdocument accessibles should
// be shut down.
ok(!isAccessibleInCache(this.iframeDoc),
"The document accessible for iframe is in cache still!");
};
}
// //////////////////////////////////////////////////////////////////////////
// Do tests
var gQueue = null;
// Debug stuff.
// gA11yEventDumpID = "eventdump";
// gA11yEventDumpToConsole = true;
function doTests() {
gQueue = new eventQueue();
gQueue.push(new changeIframeSrc("iframe", "about:"));
gQueue.push(new changeIframeSrc("iframe", "about:buildconfig"));
gQueue.push(new morphIFrame("iframe", kHide));
gQueue.push(new morphIFrame("iframe", kShow));
gQueue.push(new morphIFrame("iframe", kRemove));
gQueue.push(new makeIFrameVisible("iframe2"));
gQueue.push(new openDialogWnd("about:"));
gQueue.push(new openWndShutdownDoc());
gQueue.onFinish = doLastCallTests;
gQueue.invoke(); // Will call SimpleTest.finish();
}
function doLastCallTests() {
// ////////////////////////////////////////////////////////////////////////
// makeIFrameVisible() test, part2
// The document shouldn't have busy state (the DOM document was loaded
// before its accessible was created). Do this test lately to make sure
// the content of document accessible was created initially, prior to this
// the document accessible keeps busy state. The initial creation happens
// asynchronously after document creation, there are no events we could
// use to catch it.
var iframeDoc = getAccessible("iframe2").firstChild;
testStates(iframeDoc, 0, 0, STATE_BUSY);
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTests);
</script>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=420845"
title="Fire event_reorder on any embedded frames/iframes whos document has just loaded">
Mozilla Bug 420845
</a><br>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=506206"
title="Fire event_reorder application root accessible">
Mozilla Bug 506206
</a><br>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=566103"
title="Reorganize accessible document handling">
Mozilla Bug 566103
</a><br>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=571459"
title="Shutdown document accessible when presshell goes away">
Mozilla Bug 571459
</a>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=658185"
title="The DOM document loaded before it's shown shouldn't have busy state">
Mozilla Bug 658185
</a>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=754165"
title="Fire document load events on iframes too">
Mozilla Bug 754165
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<div id="testContainer"><iframe id="iframe"></iframe></div>
<div id="testContainer2"><iframe id="iframe2" src="about:" style="visibility: hidden;"></iframe></div>
<div id="eventdump"></div>
</body>
</html>

Просмотреть файл

@ -13,6 +13,7 @@ A11Y_MANIFESTS += [
'editabletext/a11y.ini',
'elm/a11y.ini',
'events/a11y.ini',
'events/docload/a11y.ini',
'focus/a11y.ini',
'hittest/a11y.ini',
'hyperlink/a11y.ini',

Просмотреть файл

@ -42,6 +42,10 @@ ia2Accessible::QueryInterface(REFIID iid, void** ppv)
*ppv = nullptr;
// NOTE: If any new versions of IAccessible2 are added here, they should
// also be added to the IA2 Handler in
// /accessible/ipc/win/handler/AccessibleHandler.cpp
if (IID_IAccessible2_3 == iid)
*ppv = static_cast<IAccessible2_3*>(this);
else if (IID_IAccessible2_2 == iid)

Просмотреть файл

@ -43,6 +43,7 @@
#include "nsEventMap.h"
#include "nsArrayUtils.h"
#include "mozilla/Preferences.h"
#include "mozilla/ReverseIterator.h"
#include "nsIXULRuntime.h"
#include "mozilla/mscom/AsyncInvoker.h"
@ -1136,6 +1137,35 @@ AccessibleWrap::SetID(uint32_t aID)
mID = aID;
}
static bool
IsHandlerInvalidationNeeded(uint32_t aEvent)
{
// We want to return true for any events that would indicate that something
// in the handler cache is out of date.
switch (aEvent) {
case EVENT_OBJECT_STATECHANGE:
case EVENT_OBJECT_LOCATIONCHANGE:
case EVENT_OBJECT_NAMECHANGE:
case EVENT_OBJECT_DESCRIPTIONCHANGE:
case EVENT_OBJECT_VALUECHANGE:
case IA2_EVENT_ACTION_CHANGED:
case IA2_EVENT_DOCUMENT_LOAD_COMPLETE:
case IA2_EVENT_DOCUMENT_LOAD_STOPPED:
case IA2_EVENT_DOCUMENT_ATTRIBUTE_CHANGED:
case IA2_EVENT_DOCUMENT_CONTENT_CHANGED:
case IA2_EVENT_PAGE_CHANGED:
case IA2_EVENT_TEXT_ATTRIBUTE_CHANGED:
case IA2_EVENT_TEXT_CHANGED:
case IA2_EVENT_TEXT_INSERTED:
case IA2_EVENT_TEXT_REMOVED:
case IA2_EVENT_TEXT_UPDATED:
case IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED:
return true;
default:
return false;
}
}
void
AccessibleWrap::FireWinEvent(Accessible* aTarget, uint32_t aEventType)
{
@ -1158,6 +1188,10 @@ AccessibleWrap::FireWinEvent(Accessible* aTarget, uint32_t aEventType)
return;
}
if (IsHandlerInvalidationNeeded(winEvent)) {
InvalidateHandlers();
}
// Fire MSAA event for client area window.
::NotifyWinEvent(winEvent, hwnd, OBJID_CLIENT, childID);
@ -1659,6 +1693,38 @@ AccessibleWrap::SetHandlerControl(DWORD aPid, RefPtr<IHandlerControl> aCtrl)
sHandlerControllers->AppendElement(Move(ctrlData));
}
/* static */
void
AccessibleWrap::InvalidateHandlers()
{
static const HRESULT kErrorServerDied =
HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE);
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(NS_IsMainThread());
if (!sHandlerControllers || sHandlerControllers->IsEmpty()) {
return;
}
// We iterate in reverse so that we may safely remove defunct elements while
// executing the loop.
for (auto& controller : Reversed(*sHandlerControllers)) {
MOZ_ASSERT(controller.mPid);
MOZ_ASSERT(controller.mCtrl);
ASYNC_INVOKER_FOR(IHandlerControl) invoker(controller.mCtrl,
Some(controller.mIsProxy));
HRESULT hr = ASYNC_INVOKE(invoker, Invalidate);
if (hr == CO_E_OBJNOTCONNECTED || hr == kErrorServerDied) {
sHandlerControllers->RemoveElement(controller);
} else {
NS_WARN_IF(FAILED(hr));
}
}
}
bool
AccessibleWrap::DispatchTextChangeToHandler(bool aIsInsert,

Просмотреть файл

@ -199,6 +199,8 @@ public:
static void SetHandlerControl(DWORD aPid, RefPtr<IHandlerControl> aCtrl);
static void InvalidateHandlers();
bool DispatchTextChangeToHandler(bool aIsInsert, const nsString& aText,
int32_t aStart, uint32_t aLen);

Просмотреть файл

@ -31,7 +31,7 @@ subsuite = clipboard
[browser_newtab_drop_preview.js]
[browser_newtab_focus.js]
[browser_newtab_fullscreen_focus.js]
skip-if = os == "mac" && debug # bug 1394963
skip-if = os == "mac" # bug 1394963
[browser_newtab_perwindow_private_browsing.js]
[browser_newtab_reflow_load.js]
support-files =

Просмотреть файл

@ -60,6 +60,18 @@ const EXPECTED_REFLOWS_FIRST_OPEN = [
times: 60, // This number should only ever go down - never up.
},
{
stack: [
"_handleOverflow@chrome://global/content/bindings/autocomplete.xml",
"handleOverUnderflow@chrome://global/content/bindings/autocomplete.xml",
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openPopup@chrome://global/content/bindings/autocomplete.xml",
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
],
times: 6, // This number should only ever go down - never up.
},
// Bug 1359989
{
stack: [

Просмотреть файл

@ -60,6 +60,18 @@ const EXPECTED_REFLOWS_FIRST_OPEN = [
times: 60, // This number should only ever go down - never up.
},
{
stack: [
"_handleOverflow@chrome://global/content/bindings/autocomplete.xml",
"handleOverUnderflow@chrome://global/content/bindings/autocomplete.xml",
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openPopup@chrome://global/content/bindings/autocomplete.xml",
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
],
times: 6, // This number should only ever go down - never up.
},
// Bug 1359989
{
stack: [

Просмотреть файл

@ -1815,15 +1815,6 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
onget="return this._margins;">
<setter>
<![CDATA[
if (val == this._margins) {
return val;
}
if (val && this._margins && val.start == this._margins.start &&
val.end == this._margins.end) {
return val;
}
this._margins = val;
if (val) {
@ -1840,9 +1831,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
this.style.removeProperty("--item-padding-start");
this.style.removeProperty("--item-padding-end");
}
for (let item of this.richlistbox.childNodes) {
item.handleOverUnderflow();
}
return val;
]]>
</setter>
@ -1904,6 +1893,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
// 250px". Do this *before* adding any items because when the new
// value of the margins are different from the previous value, over-
// and underflow must be handled for each item already in the popup.
let needsHandleOverUnderflow = false;
let boundToCheck = popupDirection == "rtl" ? "right" : "left";
let inputRect = this.DOMWindowUtils.getBoundsWithoutFlushing(aInput);
let startOffset = Math.abs(inputRect[boundToCheck] - documentRect[boundToCheck]);
@ -1922,17 +1912,20 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
let identityIcon = document.getElementById("identity-icon");
let identityRect =
this.DOMWindowUtils.getBoundsWithoutFlushing(identityIcon);
if (popupDirection == "rtl") {
this.margins = { start: documentRect.right - identityRect.right,
end: endOffset };
} else {
this.margins = { start: identityRect.left,
end: endOffset };
let start = popupDirection == "rtl" ?
documentRect.right - identityRect.right :
identityRect.left;
if (!this.margins || start != this.margins.start ||
endOffset != this.margins.end ||
width != this.margins.width) {
this.margins = { start, end: endOffset, width };
needsHandleOverUnderflow = true;
}
} else {
} else if (this.margins) {
// Reset the alignment so that the site icons are positioned
// according to whatever's in the CSS.
this.margins = undefined;
needsHandleOverUnderflow = true;
}
// Now that the margins have been set, start adding items (via
@ -1970,6 +1963,14 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
this.DOMWindowUtils.getBoundsWithoutFlushing(aInput).bottom);
this.openPopup(aElement, "after_start", 0, yOffset, false, false);
// Do this immediately after we've requested the popup to open. This
// will cause sync reflows but prevents flickering.
if (needsHandleOverUnderflow) {
for (let item of this.richlistbox.childNodes) {
item.handleOverUnderflow();
}
}
]]></body>
</method>

Просмотреть файл

@ -1,5 +1,5 @@
This is the PDF.js project output, https://github.com/mozilla/pdf.js
Current extension version is: 1.9.659
Current extension version is: 1.10.88
Taken from upstream commit: 3ac4baff
Taken from upstream commit: c62a1938

Просмотреть файл

@ -1990,7 +1990,7 @@ function _fetchDocument(worker, source, pdfDataRangeTransport, docId) {
if (worker.destroyed) {
return Promise.reject(new Error('Worker was destroyed'));
}
let apiVersion = '1.9.659';
let apiVersion = '1.10.88';
source.disableAutoFetch = (0, _dom_utils.getDefaultSetting)('disableAutoFetch');
source.disableStream = (0, _dom_utils.getDefaultSetting)('disableStream');
source.chunkedViewerLoading = !!pdfDataRangeTransport;
@ -3311,8 +3311,8 @@ var _UnsupportedManager = function UnsupportedManagerClosure() {
}();
var version, build;
{
exports.version = version = '1.9.659';
exports.build = build = '3ac4baff';
exports.version = version = '1.10.88';
exports.build = build = 'c62a1938';
}
exports.getDocument = getDocument;
exports.LoopbackPort = LoopbackPort;
@ -5051,8 +5051,8 @@ exports.SVGGraphics = SVGGraphics;
"use strict";
var pdfjsVersion = '1.9.659';
var pdfjsBuild = '3ac4baff';
var pdfjsVersion = '1.10.88';
var pdfjsBuild = 'c62a1938';
var pdfjsSharedUtil = __w_pdfjs_require__(0);
var pdfjsDisplayGlobal = __w_pdfjs_require__(13);
var pdfjsDisplayAPI = __w_pdfjs_require__(3);
@ -8177,8 +8177,8 @@ if (!_global_scope2.default.PDFJS) {
}
var PDFJS = _global_scope2.default.PDFJS;
{
PDFJS.version = '1.9.659';
PDFJS.build = '3ac4baff';
PDFJS.version = '1.10.88';
PDFJS.build = 'c62a1938';
}
PDFJS.pdfBug = false;
if (PDFJS.verbosity !== undefined) {

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -71,5 +71,19 @@ this.LightweightThemes = {
});
},
},
compactLight: {
selectors: ["#navigator-toolbox"],
applyConfig() {
LightweightThemeManager.currentTheme = LightweightThemeManager.getUsedTheme("firefox-compact-light@mozilla.org");
},
},
compactDark: {
selectors: ["#navigator-toolbox"],
applyConfig() {
LightweightThemeManager.currentTheme = LightweightThemeManager.getUsedTheme("firefox-compact-dark@mozilla.org");
},
},
},
};

Просмотреть файл

@ -58,7 +58,7 @@ def rust_compiler(rustc_info, cargo_info):
You can install rust by running './mach bootstrap'
or by directly running the installer from https://rustup.rs/
'''))
rustc_min_version = Version('1.20.0')
rustc_min_version = Version('1.21.0')
cargo_min_version = Version('0.{}'.format(rustc_min_version.minor + 1))
version = rustc_info.version

Просмотреть файл

@ -1441,7 +1441,7 @@ already_AddRefed<SystemPrincipal>
nsScriptSecurityManager::SystemPrincipalSingletonConstructor()
{
if (gScriptSecMan)
return do_AddRef(gScriptSecMan->mSystemPrincipal.get()).downcast<SystemPrincipal>();
return do_AddRef(gScriptSecMan->mSystemPrincipal).downcast<SystemPrincipal>();
return nullptr;
}

Просмотреть файл

@ -0,0 +1,14 @@
/* 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/. */
"use strict";
const { createEnum } = require("devtools/client/shared/enum");
createEnum([
// Update the entire changes state with the new list of changes.
"UPDATE_CHANGES",
], module.exports);

Просмотреть файл

@ -0,0 +1,9 @@
# -*- 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/.
DevToolsModules(
'index.js',
)

Просмотреть файл

@ -0,0 +1,52 @@
/* 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/. */
"use strict";
const { createFactory, createElement } = require("devtools/client/shared/vendor/react");
const { Provider } = require("devtools/client/shared/vendor/react-redux");
const ChangesApp = createFactory(require("./components/ChangesApp"));
const { LocalizationHelper } = require("devtools/shared/l10n");
const INSPECTOR_L10N =
new LocalizationHelper("devtools/client/locales/inspector.properties");
class ChangesView {
constructor(inspector, window) {
this.document = window.document;
this.inspector = inspector;
this.store = inspector.store;
this.init();
}
init() {
if (!this.inspector) {
return;
}
let changesApp = ChangesApp({});
let provider = createElement(Provider, {
id: "changesview",
key: "changesview",
store: this.store,
title: INSPECTOR_L10N.getStr("inspector.sidebar.changesViewTitle")
}, changesApp);
// Expose the provider to let inspector.js use it in setupSidebar.
this.provider = provider;
}
destroy() {
this.document = null;
this.inspector = null;
this.store = null;
}
}
module.exports = ChangesView;

Просмотреть файл

@ -0,0 +1,27 @@
/* 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/. */
"use strict";
const {
DOM: dom,
PureComponent,
} = require("devtools/client/shared/vendor/react");
const { connect } = require("devtools/client/shared/vendor/react-redux");
class ChangesApp extends PureComponent {
static get propTypes() {
return {};
}
render() {
return dom.div(
{
id: "changes-container",
}
);
}
}
module.exports = connect(state => state)(ChangesApp);

Просмотреть файл

@ -0,0 +1,9 @@
# -*- 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/.
DevToolsModules(
'ChangesApp.js',
)

Просмотреть файл

@ -0,0 +1,15 @@
# -*- 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/.
DIRS += [
'actions',
'components',
'reducers',
]
DevToolsModules(
'changes.js',
)

Просмотреть файл

@ -0,0 +1,19 @@
/* 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/. */
"use strict";
const INITIAL_CHANGES = [];
let reducers = {
};
module.exports = function (changes = INITIAL_CHANGES, action) {
let reducer = reducers[action.type];
if (!reducer) {
return changes;
}
return reducer(changes, action);
};

Просмотреть файл

@ -0,0 +1,7 @@
/* 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/. */
"use strict";
exports.changes = require("./changes");

Просмотреть файл

@ -0,0 +1,10 @@
# -*- 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/.
DevToolsModules(
'changes.js',
'index.js',
)

Просмотреть файл

@ -0,0 +1,14 @@
/* 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/. */
"use strict";
const { createEnum } = require("devtools/client/shared/enum");
createEnum([
// Update the entire events state with the new list of events.
"UPDATE_EVENTS",
], module.exports);

Просмотреть файл

@ -0,0 +1,9 @@
# -*- 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/.
DevToolsModules(
'index.js',
)

Просмотреть файл

@ -0,0 +1,27 @@
/* 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/. */
"use strict";
const {
DOM: dom,
PureComponent,
} = require("devtools/client/shared/vendor/react");
const { connect } = require("devtools/client/shared/vendor/react-redux");
class EventsApp extends PureComponent {
static get propTypes() {
return {};
}
render() {
return dom.div(
{
id: "events-container",
}
);
}
}
module.exports = connect(state => state)(EventsApp);

Просмотреть файл

@ -0,0 +1,9 @@
# -*- 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/.
DevToolsModules(
'EventsApp.js',
)

Просмотреть файл

@ -0,0 +1,52 @@
/* 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/. */
"use strict";
const { createFactory, createElement } = require("devtools/client/shared/vendor/react");
const { Provider } = require("devtools/client/shared/vendor/react-redux");
const EventsApp = createFactory(require("./components/EventsApp"));
const { LocalizationHelper } = require("devtools/shared/l10n");
const INSPECTOR_L10N =
new LocalizationHelper("devtools/client/locales/inspector.properties");
class EventsView {
constructor(inspector, window) {
this.document = window.document;
this.inspector = inspector;
this.store = inspector.store;
this.init();
}
init() {
if (!this.inspector) {
return;
}
let eventsApp = EventsApp({});
let provider = createElement(Provider, {
id: "eventsview",
key: "eventsview",
store: this.store,
title: INSPECTOR_L10N.getStr("inspector.sidebar.eventsViewTitle")
}, eventsApp);
// Expose the provider to let inspector.js use it in setupSidebar.
this.provider = provider;
}
destroy() {
this.document = null;
this.inspector = null;
this.store = null;
}
}
module.exports = EventsView;

Просмотреть файл

@ -0,0 +1,15 @@
# -*- 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/.
DIRS += [
'actions',
'components',
'reducers',
]
DevToolsModules(
'events.js',
)

Просмотреть файл

@ -0,0 +1,19 @@
/* 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/. */
"use strict";
const INITIAL_EVENTS = [];
let reducers = {
};
module.exports = function (events = INITIAL_EVENTS, action) {
let reducer = reducers[action.type];
if (!reducer) {
return events;
}
return reducer(events, action);
};

Просмотреть файл

@ -0,0 +1,7 @@
/* 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/. */
"use strict";
exports.events = require("./events");

Просмотреть файл

@ -0,0 +1,10 @@
# -*- 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/.
DevToolsModules(
'events.js',
'index.js',
)

Просмотреть файл

@ -4,10 +4,7 @@
"use strict";
const {
createElement, createFactory,
} = require("devtools/client/shared/vendor/react");
const { createElement, createFactory } = require("devtools/client/shared/vendor/react");
const { Provider } = require("devtools/client/shared/vendor/react-redux");
const ExtensionSidebarComponent = createFactory(require("./components/ExtensionSidebar"));

Просмотреть файл

@ -8,4 +8,7 @@ const { createEnum } = require("devtools/client/shared/enum");
createEnum([
// Update the entire flexboxes state with the new list of flexboxes.
"UPDATE_FLEXBOXES",
], module.exports);

Просмотреть файл

@ -4,6 +4,14 @@
"use strict";
const { PropTypes } = require("devtools/client/shared/vendor/react");
exports.flexbox = {
// The id of the flexbox container.
id: PropTypes.number,
// The node front of the flexbox container.
nodeFront: PropTypes.object,
};

Просмотреть файл

@ -20,7 +20,7 @@ const Types = require("../types");
const PREVIEW_UPDATE_DELAY = 150;
class App extends PureComponent {
class FontsApp extends PureComponent {
static get propTypes() {
return {
fonts: PropTypes.arrayOf(PropTypes.shape(Types.font)).isRequired,
@ -74,4 +74,4 @@ class App extends PureComponent {
}
}
module.exports = connect(state => state)(App);
module.exports = connect(state => state)(FontsApp);

Просмотреть файл

@ -5,7 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
'App.js',
'Font.js',
'FontList.js',
'FontsApp.js',
)

Просмотреть файл

@ -6,7 +6,6 @@
"use strict";
const { Task } = require("devtools/shared/task");
const { getColor } = require("devtools/client/shared/theme");
const { createFactory, createElement } = require("devtools/client/shared/vendor/react");
@ -14,7 +13,7 @@ const { Provider } = require("devtools/client/shared/vendor/react-redux");
const { gDevTools } = require("devtools/client/framework/devtools");
const App = createFactory(require("./components/App"));
const FontsApp = createFactory(require("./components/FontsApp"));
const { LocalizationHelper } = require("devtools/shared/l10n");
const INSPECTOR_L10N =
@ -23,29 +22,30 @@ const INSPECTOR_L10N =
const { updateFonts } = require("./actions/fonts");
const { updatePreviewText, updateShowAllFonts } = require("./actions/font-options");
function FontInspector(inspector, window) {
this.document = window.document;
this.inspector = inspector;
this.pageStyle = this.inspector.pageStyle;
this.store = this.inspector.store;
class FontInspector {
this.update = this.update.bind(this);
constructor(inspector, window) {
this.document = window.document;
this.inspector = inspector;
this.pageStyle = this.inspector.pageStyle;
this.store = this.inspector.store;
this.onNewNode = this.onNewNode.bind(this);
this.onPreviewFonts = this.onPreviewFonts.bind(this);
this.onShowAllFont = this.onShowAllFont.bind(this);
this.onThemeChanged = this.onThemeChanged.bind(this);
this.update = this.update.bind(this);
this.init();
}
this.onNewNode = this.onNewNode.bind(this);
this.onPreviewFonts = this.onPreviewFonts.bind(this);
this.onShowAllFont = this.onShowAllFont.bind(this);
this.onThemeChanged = this.onThemeChanged.bind(this);
this.init();
}
FontInspector.prototype = {
init() {
if (!this.inspector) {
return;
}
let app = App({
let fontsApp = FontsApp({
onPreviewFonts: this.onPreviewFonts,
onShowAllFont: this.onShowAllFont,
});
@ -55,7 +55,7 @@ FontInspector.prototype = {
key: "fontinspector",
store: this.store,
title: INSPECTOR_L10N.getStr("inspector.sidebar.fontInspectorTitle"),
}, app);
}, fontsApp);
// Expose the provider to let inspector.js use it in setupSidebar.
this.provider = provider;
@ -69,13 +69,13 @@ FontInspector.prototype = {
this.store.dispatch(updatePreviewText(""));
this.store.dispatch(updateShowAllFonts(false));
this.update(false, "");
},
}
/**
* Destruction function called when the inspector is destroyed. Removes event listeners
* and cleans up references.
*/
destroy: function () {
destroy() {
this.inspector.selection.off("new-node-front", this.onNewNode);
this.inspector.sidebar.off("fontinspector-selected", this.onNewNode);
gDevTools.off("theme-switched", this.onThemeChanged);
@ -84,7 +84,7 @@ FontInspector.prototype = {
this.inspector = null;
this.pageStyle = null;
this.store = null;
},
}
/**
* Returns true if the font inspector panel is visible, and false otherwise.
@ -92,7 +92,7 @@ FontInspector.prototype = {
isPanelVisible() {
return this.inspector.sidebar &&
this.inspector.sidebar.getCurrentTabID() === "fontinspector";
},
}
/**
* Selection 'new-node' event handler.
@ -102,7 +102,23 @@ FontInspector.prototype = {
this.store.dispatch(updateShowAllFonts(false));
this.update();
}
},
}
/**
* Handler for change in preview input.
*/
onPreviewFonts(value) {
this.store.dispatch(updatePreviewText(value));
this.update();
}
/**
* Handler for click on show all fonts button.
*/
onShowAllFont() {
this.store.dispatch(updateShowAllFonts(true));
this.update();
}
/**
* Handler for the "theme-switched" event.
@ -111,25 +127,9 @@ FontInspector.prototype = {
if (frame === this.document.defaultView) {
this.update();
}
},
}
/**
* Handler for change in preview input.
*/
onPreviewFonts(value) {
this.store.dispatch(updatePreviewText(value));
this.update();
},
/**
* Handler for click on show all fonts button.
*/
onShowAllFont() {
this.store.dispatch(updateShowAllFonts(true));
this.update();
},
update: Task.async(function* () {
async update() {
// Stop refreshing if the inspector or store is already destroyed.
if (!this.inspector || !this.store) {
return;
@ -158,10 +158,10 @@ FontInspector.prototype = {
};
if (showAllFonts) {
fonts = yield this.pageStyle.getAllUsedFontFaces(options)
fonts = await this.pageStyle.getAllUsedFontFaces(options)
.catch(console.error);
} else {
fonts = yield this.pageStyle.getUsedFontFaces(node, options)
fonts = await this.pageStyle.getUsedFontFaces(node, options)
.catch(console.error);
}
@ -172,7 +172,7 @@ FontInspector.prototype = {
}
for (let font of fonts) {
font.previewUrl = yield font.preview.data.string();
font.previewUrl = await font.preview.data.string();
}
// in case we've been destroyed in the meantime
@ -183,7 +183,8 @@ FontInspector.prototype = {
this.store.dispatch(updateFonts(fonts));
this.inspector.emit("fontinspector-updated");
})
};
}
}
module.exports = FontInspector;

Просмотреть файл

@ -5,7 +5,6 @@
"use strict";
const Services = require("Services");
const { Task } = require("devtools/shared/task");
const SwatchColorPickerTooltip = require("devtools/client/shared/widgets/tooltip/SwatchColorPickerTooltip");
const { throttle } = require("devtools/client/inspector/shared/utils");
@ -44,45 +43,45 @@ const GRID_COLORS = [
"#005A71"
];
function GridInspector(inspector, window) {
this.document = window.document;
this.highlighters = inspector.highlighters;
this.inspector = inspector;
this.store = inspector.store;
this.telemetry = inspector.telemetry;
this.walker = this.inspector.walker;
class GridInspector {
this.getSwatchColorPickerTooltip = this.getSwatchColorPickerTooltip.bind(this);
this.updateGridPanel = this.updateGridPanel.bind(this);
constructor(inspector, window) {
this.document = window.document;
this.highlighters = inspector.highlighters;
this.inspector = inspector;
this.store = inspector.store;
this.telemetry = inspector.telemetry;
this.walker = this.inspector.walker;
this.onHighlighterChange = this.onHighlighterChange.bind(this);
this.onNavigate = this.onNavigate.bind(this);
this.onReflow = throttle(this.onReflow, 500, this);
this.onSetGridOverlayColor = this.onSetGridOverlayColor.bind(this);
this.onShowGridAreaHighlight = this.onShowGridAreaHighlight.bind(this);
this.onShowGridCellHighlight = this.onShowGridCellHighlight.bind(this);
this.onShowGridLineNamesHighlight = this.onShowGridLineNamesHighlight.bind(this);
this.onSidebarSelect = this.onSidebarSelect.bind(this);
this.onToggleGridHighlighter = this.onToggleGridHighlighter.bind(this);
this.onToggleShowGridAreas = this.onToggleShowGridAreas.bind(this);
this.onToggleShowGridLineNumbers = this.onToggleShowGridLineNumbers.bind(this);
this.onToggleShowInfiniteLines = this.onToggleShowInfiniteLines.bind(this);
this.getSwatchColorPickerTooltip = this.getSwatchColorPickerTooltip.bind(this);
this.updateGridPanel = this.updateGridPanel.bind(this);
this.init();
}
this.onHighlighterChange = this.onHighlighterChange.bind(this);
this.onNavigate = this.onNavigate.bind(this);
this.onReflow = throttle(this.onReflow, 500, this);
this.onSetGridOverlayColor = this.onSetGridOverlayColor.bind(this);
this.onShowGridAreaHighlight = this.onShowGridAreaHighlight.bind(this);
this.onShowGridCellHighlight = this.onShowGridCellHighlight.bind(this);
this.onShowGridLineNamesHighlight = this.onShowGridLineNamesHighlight.bind(this);
this.onSidebarSelect = this.onSidebarSelect.bind(this);
this.onToggleGridHighlighter = this.onToggleGridHighlighter.bind(this);
this.onToggleShowGridAreas = this.onToggleShowGridAreas.bind(this);
this.onToggleShowGridLineNumbers = this.onToggleShowGridLineNumbers.bind(this);
this.onToggleShowInfiniteLines = this.onToggleShowInfiniteLines.bind(this);
GridInspector.prototype = {
this.init();
}
/**
* Initializes the grid inspector by fetching the LayoutFront from the walker, loading
* the highlighter settings and initalizing the SwatchColorPicker instance.
*/
init: Task.async(function* () {
async init() {
if (!this.inspector) {
return;
}
this.layoutInspector = yield this.inspector.walker.getLayoutInspector();
this.layoutInspector = await this.inspector.walker.getLayoutInspector();
this.loadHighlighterSettings();
@ -101,7 +100,7 @@ GridInspector.prototype = {
this.inspector.on("new-root", this.onNavigate);
this.onSidebarSelect();
}),
}
/**
* Destruction function called when the inspector is destroyed. Removes event listeners
@ -128,7 +127,7 @@ GridInspector.prototype = {
this.store = null;
this.swatchColorPickerTooltip = null;
this.walker = null;
},
}
getComponentProps() {
return {
@ -142,7 +141,7 @@ GridInspector.prototype = {
onToggleShowGridLineNumbers: this.onToggleShowGridLineNumbers,
onToggleShowInfiniteLines: this.onToggleShowInfiniteLines,
};
},
}
/**
* Returns the initial color linked to a grid container. Will attempt to check the
@ -169,7 +168,7 @@ GridInspector.prototype = {
}
return color || fallbackColor;
},
}
/**
* Returns the color set for the grid highlighter associated with the provided
@ -188,7 +187,7 @@ GridInspector.prototype = {
}
return null;
},
}
/**
* Create a highlighter settings object for the provided nodeFront.
@ -206,14 +205,14 @@ GridInspector.prototype = {
return Object.assign({}, highlighterSettings, {
color
});
},
}
/**
* Retrieve the shared SwatchColorPicker instance.
*/
getSwatchColorPickerTooltip() {
return this.swatchColorPickerTooltip;
},
}
/**
* Given a list of new grid fronts, and if we have a currently highlighted grid, check
@ -239,7 +238,7 @@ GridInspector.prototype = {
const newFragments = newGridFront.gridFragments;
return !compareFragmentsGeometry(oldFragments, newFragments);
},
}
/**
* Returns true if the layout panel is visible, and false otherwise.
@ -248,7 +247,7 @@ GridInspector.prototype = {
return this.inspector && this.inspector.toolbox && this.inspector.sidebar &&
this.inspector.toolbox.currentToolId === "inspector" &&
this.inspector.sidebar.getCurrentTabID() === "layoutview";
},
}
/**
* Load the grid highligher display settings into the store from the stored preferences.
@ -263,7 +262,7 @@ GridInspector.prototype = {
dispatch(updateShowGridAreas(showGridAreas));
dispatch(updateShowGridLineNumbers(showGridLineNumbers));
dispatch(updateShowInfiniteLines(showInfinteLines));
},
}
showGridHighlighter(node, settings) {
this.lastHighlighterColor = settings.color;
@ -271,7 +270,7 @@ GridInspector.prototype = {
this.lastHighlighterState = true;
this.highlighters.showGridHighlighter(node, settings);
},
}
toggleGridHighlighter(node, settings) {
this.lastHighlighterColor = settings.color;
@ -279,13 +278,13 @@ GridInspector.prototype = {
this.lastHighlighterState = node !== this.highlighters.gridHighlighterShown;
this.highlighters.toggleGridHighlighter(node, settings, "grid");
},
}
/**
* Updates the grid panel by dispatching the new grid data. This is called when the
* layout view becomes visible or the view needs to be updated with new grid data.
*/
updateGridPanel: Task.async(function* () {
async updateGridPanel() {
// Stop refreshing if the inspector or store is already destroyed.
if (!this.inspector || !this.store) {
return;
@ -294,7 +293,7 @@ GridInspector.prototype = {
// Get all the GridFront from the server if no gridFronts were provided.
let gridFronts;
try {
gridFronts = yield this.layoutInspector.getAllGrids(this.walker.rootNode);
gridFronts = await this.layoutInspector.getAllGrids(this.walker.rootNode);
} catch (e) {
// This call might fail if called asynchrously after the toolbox is finished
// closing.
@ -319,7 +318,7 @@ GridInspector.prototype = {
// particular DOM Node in the tree yet, or when we are connected to an older server.
if (!nodeFront) {
try {
nodeFront = yield this.walker.getNodeFromActor(grid.actorID, ["containerEl"]);
nodeFront = await this.walker.getNodeFromActor(grid.actorID, ["containerEl"]);
} catch (e) {
// This call might fail if called asynchrously after the toolbox is finished
// closing.
@ -341,7 +340,7 @@ GridInspector.prototype = {
}
this.store.dispatch(updateGrids(grids));
}),
}
/**
* Handler for "grid-highlighter-shown" and "grid-highlighter-hidden" events emitted
@ -374,7 +373,7 @@ GridInspector.prototype = {
this.lastHighlighterColor = null;
this.lastHighlighterNode = null;
this.lastHighlighterState = null;
},
}
/**
* Handler for "new-root" event fired by the inspector, which indicates a page
@ -384,7 +383,7 @@ GridInspector.prototype = {
if (this.isPanelVisible()) {
this.updateGridPanel();
}
},
}
/**
* Handler for the "reflow" event fired by the inspector's reflow tracker. On reflows,
@ -399,7 +398,7 @@ GridInspector.prototype = {
* after the reflow, as well as the grid fragment data on the currently highlighted
* grid.
*/
onReflow: Task.async(function* () {
async onReflow() {
if (!this.isPanelVisible()) {
return;
}
@ -410,7 +409,7 @@ GridInspector.prototype = {
// The new list of grids from the server.
let newGridFronts;
try {
newGridFronts = yield this.layoutInspector.getAllGrids(this.walker.rootNode);
newGridFronts = await this.layoutInspector.getAllGrids(this.walker.rootNode);
} catch (e) {
// This call might fail if called asynchrously after the toolbox is finished
// closing.
@ -444,7 +443,7 @@ GridInspector.prototype = {
// Either the list of containers or the current fragments have changed, do update.
this.updateGridPanel(newGridFronts);
}),
}
/**
* Handler for a change in the grid overlay color picker for a grid container.
@ -467,7 +466,7 @@ GridInspector.prototype = {
this.showGridHighlighter(node, highlighterSettings);
}
}
},
}
/**
* Highlights the grid area in the CSS Grid Highlighter for the given grid.
@ -491,7 +490,7 @@ GridInspector.prototype = {
this.showGridHighlighter(node, highlighterSettings);
this.store.dispatch(updateGridHighlighted(node, true));
},
}
/**
* Highlights the grid cell in the CSS Grid Highlighter for the given grid.
@ -521,7 +520,7 @@ GridInspector.prototype = {
this.showGridHighlighter(node, highlighterSettings);
this.store.dispatch(updateGridHighlighted(node, true));
},
}
/**
* Highlights the grid line in the CSS Grid Highlighter for the given grid.
@ -554,7 +553,7 @@ GridInspector.prototype = {
this.showGridHighlighter(node, highlighterSettings);
this.store.dispatch(updateGridHighlighted(node, true));
},
}
/**
* Handler for the inspector sidebar "select" event. Starts tracking reflows
@ -569,7 +568,7 @@ GridInspector.prototype = {
this.inspector.reflowTracker.trackReflows(this, this.onReflow);
this.updateGridPanel();
},
}
/**
* Handler for a change in the input checkboxes in the GridList component.
@ -585,7 +584,7 @@ GridInspector.prototype = {
this.store.dispatch(updateGridHighlighted(node,
node !== this.highlighters.gridHighlighterShown));
},
}
/**
* Handler for a change in the show grid areas checkbox in the GridDisplaySettings
@ -611,7 +610,7 @@ GridInspector.prototype = {
this.highlighters.showGridHighlighter(grid.nodeFront, highlighterSettings);
}
}
},
}
/**
* Handler for a change in the show grid line numbers checkbox in the
@ -638,7 +637,7 @@ GridInspector.prototype = {
this.showGridHighlighter(grid.nodeFront, highlighterSettings);
}
}
},
}
/**
* Handler for a change in the extend grid lines infinitely checkbox in the
@ -665,8 +664,8 @@ GridInspector.prototype = {
this.showGridHighlighter(grid.nodeFront, highlighterSettings);
}
}
},
}
};
}
module.exports = GridInspector;

Просмотреть файл

@ -646,11 +646,64 @@ Inspector.prototype = {
this.browserRequire("devtools/client/inspector/layout/layout");
this.layoutview = new LayoutView(this, this.panelWin);
}
return this.layoutview.provider;
}
},
defaultTab == layoutId);
if (Services.prefs.getBoolPref("devtools.changesview.enabled")) {
// Inject a lazy loaded react tab by exposing a fake React object
// with a lazy defined Tab thanks to `panel` being a function
let changesId = "changesview";
let changesTitle = INSPECTOR_L10N.getStr("inspector.sidebar.changesViewTitle");
this.sidebar.addTab(
changesId,
changesTitle,
{
props: {
id: changesId,
title: changesTitle
},
panel: () => {
if (!this.changesview) {
const ChangesView =
this.browserRequire("devtools/client/inspector/changes/changes");
this.changesview = new ChangesView(this, this.panelWin);
}
return this.changesview.provider;
}
},
defaultTab == changesId);
}
if (Services.prefs.getBoolPref("devtools.eventsview.enabled")) {
// Inject a lazy loaded react tab by exposing a fake React object
// with a lazy defined Tab thanks to `panel` being a function
let eventsId = "eventsview";
let eventsTitle = INSPECTOR_L10N.getStr("inspector.sidebar.eventsViewTitle");
this.sidebar.addTab(
eventsId,
eventsTitle,
{
props: {
id: eventsId,
title: eventsTitle
},
panel: () => {
if (!this.eventview) {
const EventsView =
this.browserRequire("devtools/client/inspector/events/events");
this.eventsview = new EventsView(this, this.panelWin);
}
return this.eventsview.provider;
}
},
defaultTab == eventsId);
}
if (this.target.form.animationsActor) {
this.sidebar.addFrameTab(
"animationinspector",
@ -678,6 +731,7 @@ Inspector.prototype = {
this.browserRequire("devtools/client/inspector/fonts/fonts");
this.fontinspector = new FontInspector(this, this.panelWin);
}
return this.fontinspector.provider;
}
},

Просмотреть файл

@ -35,7 +35,7 @@ const BOXMODEL_OPENED_PREF = "devtools.layout.boxmodel.opened";
const FLEXBOX_OPENED_PREF = "devtools.layout.flexbox.opened";
const GRID_OPENED_PREF = "devtools.layout.grid.opened";
class App extends PureComponent {
class LayoutApp extends PureComponent {
static get propTypes() {
return {
boxModel: PropTypes.shape(BoxModelTypes.boxModel).isRequired,
@ -102,4 +102,4 @@ class App extends PureComponent {
}
}
module.exports = connect(state => state)(App);
module.exports = connect(state => state)(LayoutApp);

Просмотреть файл

@ -7,5 +7,5 @@
DevToolsModules(
'Accordion.css',
'Accordion.js',
'App.js',
'LayoutApp.js',
)

Просмотреть файл

@ -7,7 +7,7 @@
const { createFactory, createElement } = require("devtools/client/shared/vendor/react");
const { Provider } = require("devtools/client/shared/vendor/react-redux");
const App = createFactory(require("./components/App"));
const LayoutApp = createFactory(require("./components/LayoutApp"));
const { LocalizationHelper } = require("devtools/shared/l10n");
const INSPECTOR_L10N =
@ -16,15 +16,15 @@ const INSPECTOR_L10N =
loader.lazyRequireGetter(this, "FlexboxInspector", "devtools/client/inspector/flexbox/flexbox");
loader.lazyRequireGetter(this, "GridInspector", "devtools/client/inspector/grids/grid-inspector");
function LayoutView(inspector, window) {
this.document = window.document;
this.inspector = inspector;
this.store = inspector.store;
class LayoutView {
this.init();
}
constructor(inspector, window) {
this.document = window.document;
this.inspector = inspector;
this.store = inspector.store;
LayoutView.prototype = {
this.init();
}
init() {
if (!this.inspector) {
@ -56,7 +56,7 @@ LayoutView.prototype = {
onToggleShowInfiniteLines,
} = this.gridInspector.getComponentProps();
let app = App({
let layoutApp = LayoutApp({
getSwatchColorPickerTooltip,
setSelectedNode,
/**
@ -84,11 +84,11 @@ LayoutView.prototype = {
key: "layoutview",
store: this.store,
title: INSPECTOR_L10N.getStr("inspector.sidebar.layoutViewTitle2"),
}, app);
}, layoutApp);
// Expose the provider to let inspector.js use it in setupSidebar.
this.provider = provider;
},
}
/**
* Destruction function called when the inspector is destroyed. Cleans up references.
@ -99,8 +99,8 @@ LayoutView.prototype = {
this.document = null;
this.inspector = null;
this.store = null;
},
}
};
}
module.exports = LayoutView;

Просмотреть файл

@ -4,8 +4,10 @@
DIRS += [
'boxmodel',
'changes',
'components',
'computed',
'events',
'extensions',
'flexbox',
'fonts',

Просмотреть файл

@ -8,6 +8,8 @@
// settings.
exports.boxModel = require("devtools/client/inspector/boxmodel/reducers/box-model");
exports.changes = require("devtools/client/inspector/changes/reducers/changes");
exports.events = require("devtools/client/inspector/events/reducers/events");
exports.extensionsSidebar = require("devtools/client/inspector/extensions/reducers/sidebar");
exports.flexboxes = require("devtools/client/inspector/flexbox/reducers/flexboxes");
exports.fontOptions = require("devtools/client/inspector/fonts/reducers/font-options");

Просмотреть файл

@ -7,11 +7,13 @@ support-files =
csp_json.json
csp_json.json^headers^
doc_frame_script.js
empty.html
head.js
invalid_json.json
invalid_json.json^headers^
manifest_json.json
manifest_json.json^headers^
passthrough-sw.js
simple_json.json
simple_json.json^headers^
valid_json.json
@ -48,3 +50,4 @@ support-files =
[browser_jsonview_slash.js]
[browser_jsonview_valid_json.js]
[browser_json_refresh.js]
[browser_jsonview_serviceworker.js]

Просмотреть файл

@ -0,0 +1,73 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const TEST_JSON_URL = URL_ROOT + "valid_json.json";
const EMPTY_PAGE = URL_ROOT + "empty.html";
const SW = URL_ROOT + "passthrough-sw.js";
add_task(async function () {
info("Test valid JSON with service worker started");
await SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true],
]});
let swTab = BrowserTestUtils.addTab(gBrowser, EMPTY_PAGE);
let browser = gBrowser.getBrowserForTab(swTab);
await BrowserTestUtils.browserLoaded(browser);
await ContentTask.spawn(browser, { script: SW, scope: TEST_JSON_URL }, async opts => {
let reg = await content.navigator.serviceWorker.register(opts.script,
{ scope: opts.scope });
return new content.window.Promise(resolve => {
let worker = reg.installing;
if (worker.state === "activated") {
resolve();
return;
}
worker.addEventListener("statechange", evt => {
if (worker.state === "activated") {
resolve();
}
});
});
});
let tab = await addJsonViewTab(TEST_JSON_URL);
ok(tab.linkedBrowser.contentPrincipal.isNullPrincipal, "Should have null principal");
is(await countRows(), 3, "There must be three rows");
let objectCellCount = await getElementCount(
".jsonPanelBox .treeTable .objectCell");
is(objectCellCount, 1, "There must be one object cell");
let objectCellText = await getElementText(
".jsonPanelBox .treeTable .objectCell");
is(objectCellText, "", "The summary is hidden when object is expanded");
// Clicking the value does not collapse it (so that it can be selected and copied).
await clickJsonNode(".jsonPanelBox .treeTable .treeValueCell");
is(await countRows(), 3, "There must still be three rows");
// Clicking the label collapses the auto-expanded node.
await clickJsonNode(".jsonPanelBox .treeTable .treeLabel");
is(await countRows(), 1, "There must be one row");
await ContentTask.spawn(browser, { script: SW, scope: TEST_JSON_URL }, async opts => {
let reg = await content.navigator.serviceWorker.getRegistration(opts.scope);
await reg.unregister();
});
await BrowserTestUtils.removeTab(swTab);
});
function countRows() {
return getElementCount(".jsonPanelBox .treeTable .treeRow");
}

Просмотреть файл

@ -0,0 +1 @@
<!doctype html>

Просмотреть файл

@ -0,0 +1,5 @@
"use strict";
addEventListener("fetch", evt => {
evt.respondWith(fetch(evt.request));
});

Просмотреть файл

@ -349,6 +349,16 @@ inspector.sidebar.layoutViewTitle2=Layout
# name. Used to promote new/recent panels such as the layout panel.
inspector.sidebar.newBadge=new!
# LOCALIZATION NOTE (inspector.sidebar.changesViewTitle):
# This is the title shown in a tab in the side panel of the Inspector panel
# that corresponds to the tool displaying CSS changes.
inspector.sidebar.changesViewTitle=Changes
# LOCALIZATION NOTE (inspector.sidebar.eventsViewTitle):
# This is the title shown in a tab in the side panel of the Inspector panel
# that corresponds to the tool displaying the list of event listeners used in the page.
inspector.sidebar.eventsViewTitle=Events
# LOCALIZATION NOTE (inspector.sidebar.animationInspectorTitle):
# This is the title shown in a tab in the side panel of the Inspector panel
# that corresponds to the tool displaying animations defined in the page.

Просмотреть файл

@ -60,7 +60,10 @@ pref("devtools.inspector.showAllAnonymousContent", false);
pref("devtools.inspector.colorWidget.enabled", false);
// Enable the CSS shapes highlighter
pref("devtools.inspector.shapesHighlighter.enabled", true);
// Enable the Changes View
pref("devtools.changesview.enabled", false);
// Enable the Events View
pref("devtools.eventsview.enabled", false);
// Enable the Flexbox Inspector
pref("devtools.flexboxinspector.enabled", false);

Просмотреть файл

@ -12,7 +12,9 @@ const { AppConstants } = devtools.require("resource://gre/modules/AppConstants.j
const BROWSER_BASED_DIRS = [
"resource://devtools/client/inspector/boxmodel",
"resource://devtools/client/inspector/changes",
"resource://devtools/client/inspector/computed",
"resource://devtools/client/inspector/events",
"resource://devtools/client/inspector/flexbox",
"resource://devtools/client/inspector/fonts",
"resource://devtools/client/inspector/grids",

Просмотреть файл

@ -1051,8 +1051,12 @@ CustomElementReactionsStack::PopAndInvokeElementQueue()
// element, see https://github.com/w3c/webcomponents/issues/635.
// We usually report the error to entry global in gecko, so just follow the
// same behavior here.
// This may be null if it's called from parser, see the case of
// attributeChangedCallback in
// https://html.spec.whatwg.org/multipage/parsing.html#create-an-element-for-the-token
// In that case, the exception of callback reactions will be automatically
// reported in CallSetup.
nsIGlobalObject* global = GetEntryGlobal();
MOZ_ASSERT(global, "Should always have a entry global here!");
InvokeReactions(elementQueue, global);
}

Просмотреть файл

@ -24,6 +24,7 @@ namespace mozilla {
namespace dom {
class Element;
class NodeInfo;
struct CustomElementDefinition;
} // namespace dom
} // namespace mozilla
@ -41,7 +42,8 @@ nsresult
NS_NewHTMLElement(mozilla::dom::Element** aResult,
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
mozilla::dom::FromParser aFromParser,
const nsAString* aIs = nullptr);
const nsAString* aIs = nullptr,
mozilla::dom::CustomElementDefinition* aDefinition = nullptr);
// First argument should be nsHTMLTag, but that adds dependency to parser
// for a bunch of files.

Просмотреть файл

@ -1596,7 +1596,8 @@ nsIDocument::nsIDocument()
mNotifiedPageForUseCounter(0),
mIncCounters(),
mUserHasInteracted(false),
mServoRestyleRootDirtyBits(0)
mServoRestyleRootDirtyBits(0),
mThrowOnDynamicMarkupInsertionCounter(0)
{
SetIsInDocument();
for (auto& cnt : mIncCounters) {
@ -2500,7 +2501,7 @@ nsDocument::MaybeDowngradePrincipal(nsIPrincipal* aPrincipal)
MOZ_ASSERT(expanded->WhiteList().Length() > 0);
return do_AddRef(expanded->WhiteList().LastElement().get());
return do_AddRef(expanded->WhiteList().LastElement());
}
if (!sChromeInContentPrefCached) {

Просмотреть файл

@ -3195,6 +3195,22 @@ public:
inline void SetServoRestyleRoot(nsINode* aRoot, uint32_t aDirtyBits);
bool ShouldThrowOnDynamicMarkupInsertion()
{
return mThrowOnDynamicMarkupInsertionCounter;
}
void IncrementThrowOnDynamicMarkupInsertionCounter()
{
++mThrowOnDynamicMarkupInsertionCounter;
}
void DecrementThrowOnDynamicMarkupInsertionCounter()
{
MOZ_ASSERT(mThrowOnDynamicMarkupInsertionCounter);
--mThrowOnDynamicMarkupInsertionCounter;
}
protected:
bool GetUseCounter(mozilla::UseCounter aUseCounter)
{
@ -3736,6 +3752,11 @@ protected:
// root corresponds to.
nsCOMPtr<nsINode> mServoRestyleRoot;
uint32_t mServoRestyleRootDirtyBits;
// Used in conjunction with the create-an-element-for-the-token algorithm to
// prevent custom element constructors from being able to use document.open(),
// document.close(), and document.write() when they are invoked by the parser.
uint32_t mThrowOnDynamicMarkupInsertionCounter;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocument, NS_IDOCUMENT_IID)
@ -3792,6 +3813,23 @@ private:
uint32_t mMicroTaskLevel;
};
class MOZ_RAII AutoSetThrowOnDynamicMarkupInsertionCounter final {
public:
explicit AutoSetThrowOnDynamicMarkupInsertionCounter(
nsIDocument* aDocument)
: mDocument(aDocument)
{
mDocument->IncrementThrowOnDynamicMarkupInsertionCounter();
}
~AutoSetThrowOnDynamicMarkupInsertionCounter() {
mDocument->DecrementThrowOnDynamicMarkupInsertionCounter();
}
private:
nsIDocument* mDocument;
};
// XXX These belong somewhere else
nsresult
NS_NewHTMLDocument(nsIDocument** aInstancePtrResult, bool aLoadedAsData = false);

Просмотреть файл

@ -702,10 +702,10 @@ TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec, const char* fun
break;
}
const gfx::IntSize destSize(mWidth, mHeight);
const gfx::IntSize dstSize(mWidth, mHeight);
const auto dstOrigin = (webgl->mPixelStore_FlipY ? gl::OriginPos::TopLeft
: gl::OriginPos::BottomLeft);
if (!gl->BlitHelper()->BlitImageToFramebuffer(mImage, destSize, dstOrigin)) {
if (!gl->BlitHelper()->BlitImageToFramebuffer(mImage, dstSize, dstOrigin)) {
fallbackReason = "likely bug: failed to blit";
break;
}

Просмотреть файл

@ -94,11 +94,6 @@ HTMLBodyElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
int32_t bodyLeftMargin = -1;
int32_t bodyRightMargin = -1;
// check the mode (fortunately, the GenericSpecifiedValues has a presContext for us to use!)
NS_ASSERTION(aData->mPresContext, "null presContext in MapAttributesIntoRule was unexpected");
nsCompatibility mode = aData->mPresContext->CompatibilityMode();
const nsAttrValue* value;
// if marginwidth/marginheight are set, reflect them as 'margin'
value = aAttributes->GetAttr(nsGkAtoms::marginwidth);
@ -177,20 +172,6 @@ HTMLBodyElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
nscoord frameMarginHeight=-1; // default value
docShell->GetMarginWidth(&frameMarginWidth); // -1 indicates not set
docShell->GetMarginHeight(&frameMarginHeight);
if (frameMarginWidth >= 0 && bodyMarginWidth == -1) { // set in <frame> & not in <body>
if (eCompatibility_NavQuirks == mode) {
if (bodyMarginHeight == -1 && 0 > frameMarginHeight) { // nav quirk
frameMarginHeight = 0;
}
}
}
if (frameMarginHeight >= 0 && bodyMarginHeight == -1) { // set in <frame> & not in <body>
if (eCompatibility_NavQuirks == mode) {
if (bodyMarginWidth == -1 && 0 > frameMarginWidth) { // nav quirk
frameMarginWidth = 0;
}
}
}
if (bodyMarginWidth == -1 && frameMarginWidth >= 0) {
if (bodyLeftMargin == -1) {

Просмотреть файл

@ -251,7 +251,8 @@ DoCustomElementCreate(Element** aElement, nsIDocument* aDoc, nsAtom* aLocalName,
nsresult
NS_NewHTMLElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
FromParser aFromParser, const nsAString* aIs)
FromParser aFromParser, const nsAString* aIs,
mozilla::dom::CustomElementDefinition* aDefinition)
{
*aResult = nullptr;
@ -268,8 +269,8 @@ NS_NewHTMLElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&&
// We only handle the "synchronous custom elements flag is set" now.
// For the unset case (e.g. cloning a node), see bug 1319342 for that.
// Step 4.
CustomElementDefinition* definition = nullptr;
if (CustomElementRegistry::IsCustomElementEnabled()) {
CustomElementDefinition* definition = aDefinition;
if (!definition && CustomElementRegistry::IsCustomElementEnabled()) {
definition =
nsContentUtils::LookupCustomElementDefinition(nodeInfo->GetDocument(),
nodeInfo->LocalName(),
@ -294,9 +295,20 @@ NS_NewHTMLElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&&
bool synchronousCustomElements = aFromParser != dom::FROM_PARSER_FRAGMENT ||
aFromParser == dom::NOT_FROM_PARSER;
// Per discussion in https://github.com/w3c/webcomponents/issues/635,
// use entry global in those places that are called from JS APIs.
nsIGlobalObject* global = GetEntryGlobal();
MOZ_ASSERT(global);
// use entry global in those places that are called from JS APIs and use the
// node document's global object if it is called from parser.
nsIGlobalObject* global;
if (aFromParser == dom::NOT_FROM_PARSER) {
global = GetEntryGlobal();
} else {
global = nodeInfo->GetDocument()->GetScopeObject();
}
if (!global) {
// In browser chrome code, one may have access to a document which doesn't
// have scope object anymore.
return NS_ERROR_FAILURE;
}
AutoEntryScript aes(global, "create custom elements");
JSContext* cx = aes.cx();
ErrorResult rv;
@ -336,6 +348,7 @@ NS_NewHTMLElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&&
// Step 6.2.
NS_IF_ADDREF(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser));
(*aResult)->SetCustomElementData(new CustomElementData(definition->mType));
nsContentUtils::EnqueueUpgradeReaction(*aResult, definition);
return NS_OK;
}

Просмотреть файл

@ -1502,6 +1502,11 @@ nsHTMLDocument::Open(JSContext* cx,
return nullptr;
}
if (ShouldThrowOnDynamicMarkupInsertion()) {
aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return nullptr;
}
nsAutoCString contentType;
contentType.AssignLiteral("text/html");
@ -1841,6 +1846,11 @@ nsHTMLDocument::Close(ErrorResult& rv)
return;
}
if (ShouldThrowOnDynamicMarkupInsertion()) {
rv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
if (!mParser || !mParser->IsScriptCreated()) {
return;
}
@ -1925,6 +1935,11 @@ nsHTMLDocument::WriteCommon(JSContext *cx,
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
if (ShouldThrowOnDynamicMarkupInsertion()) {
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
if (mParserAborted) {
// Hixie says aborting the parser doesn't undefine the insertion point.
// However, since we null out mParser in that case, we track the

Просмотреть файл

@ -18602,6 +18602,7 @@ Maintenance::DirectoryWork()
continue;
}
nsCString suffix;
nsCString group;
nsCString origin;
nsTArray<nsString> databasePaths;
@ -18659,17 +18660,17 @@ Maintenance::DirectoryWork()
// Found a database.
if (databasePaths.IsEmpty()) {
MOZ_ASSERT(suffix.IsEmpty());
MOZ_ASSERT(group.IsEmpty());
MOZ_ASSERT(origin.IsEmpty());
int64_t dummyTimeStamp;
bool dummyPersisted;
nsCString dummySuffix;
if (NS_WARN_IF(NS_FAILED(
quotaManager->GetDirectoryMetadata2(originDir,
&dummyTimeStamp,
&dummyPersisted,
dummySuffix,
suffix,
group,
origin)))) {
// Not much we can do here...
@ -18687,6 +18688,21 @@ Maintenance::DirectoryWork()
group,
origin,
Move(databasePaths)));
nsCOMPtr<nsIFile> directory;
// Idle maintenance may occur before origin is initailized.
// Ensure origin is initialized first. It will initialize all origins
// for temporary storage including IDB origins.
rv = quotaManager->EnsureOriginIsInitialized(persistenceType,
suffix,
group,
origin,
getter_AddRefs(directory));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
}
}

Просмотреть файл

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<script>
function boom()
{
var a = new AudioContext();
var b = new BroadcastChannel("x");
a.addEventListener("statechange", bye, false);
}
function bye()
{
location = "data:text/html,2";
}
</script>
</head>
<body onload="boom();"></body>
</html>

Просмотреть файл

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script>
function zombieWindow()
{
var frame = document.createElement("iframe");
document.body.appendChild(frame);
var frameWin = frame.contentWindow;
frame.remove();
return frameWin;
}
function boom() {
zombieWindow().navigator.mozGetUserMedia({ "fake": true, "audio": true }, function(stream) {}, function(e) {});
}
</script>
</head>
<body onload="boom();"></body>
</html>

Просмотреть файл

@ -14,6 +14,8 @@ load 855796.html
load 860143.html
load 861958.html
load 863929.html
load 1185191.html
load 1281695.html
load 1306476.html
load 1348381.html
load 1367930_1.html

Просмотреть файл

@ -10,6 +10,7 @@ support-files =
[test_content_element.html]
[test_custom_element_adopt_callbacks.html]
[test_custom_element_callback_innerhtml.html]
skip-if = true # disabled - See bug 1390396
[test_custom_element_clone_callbacks_extended.html]
[test_custom_element_htmlconstructor.html]
skip-if = os == 'android' # bug 1323645
@ -20,6 +21,7 @@ support-files =
[test_custom_element_in_shadow.html]
skip-if = true # disabled - See bug 1390396
[test_custom_element_register_invalid_callbacks.html]
[test_custom_element_throw_on_dynamic_markup_insertion.html]
[test_custom_element_get.html]
[test_custom_element_when_defined.html]
[test_custom_element_upgrade.html]
@ -34,7 +36,6 @@ support-files =
[test_document_adoptnode.html]
[test_document_importnode.html]
[test_document_register.html]
[test_document_register_base_queue.html]
[test_document_register_lifecycle.html]
skip-if = true # disabled - See bug 1390396
[test_document_register_parser.html]

Просмотреть файл

@ -0,0 +1,66 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1378079
-->
<head>
<title>Test throw on dynamic markup insertion when creating element synchronously from parser</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=1378079">Bug 1378079</a>
<div id="container"></div>
<script>
class DoDocumentOpenInCtor extends HTMLElement {
constructor() {
super();
document.open();
}
};
customElements.define('x-document-open-in-ctor', DoDocumentOpenInCtor);
class DoDocumentWriteInCtor extends HTMLElement {
constructor() {
super();
document.write('<div>This should not be shown</div>');
}
};
customElements.define('x-document-write-in-ctor', DoDocumentWriteInCtor);
class DoDocumentCloseInCtor extends HTMLElement {
constructor() {
super();
document.close();
}
};
customElements.define('x-document-close-in-ctor', DoDocumentCloseInCtor);
window.errors = [];
window.onerror = function(message, url, lineNumber, columnNumber, error) {
errors.push(error.name);
return true;
}
var expectedErrorCount = 0;
document.write("<x-document-open-in-ctor></x-document-open-in-ctor>");
expectedErrorCount++;
is(window.errors.length, expectedErrorCount, "expectedErrorCount should be " + expectedErrorCount);
is(window.errors[expectedErrorCount - 1], 'InvalidStateError', "Error name should be 'InvalidStateError'");
document.write("<x-document-write-in-ctor></x-document-write-in-ctor>");
expectedErrorCount++;
is(window.errors.length, expectedErrorCount, "expectedErrorCount should be " + expectedErrorCount);
is(window.errors[expectedErrorCount - 1], 'InvalidStateError', "Error name should be 'InvalidStateError'");
document.write("<x-document-close-in-ctor></x-document-close-in-ctor>");
expectedErrorCount++;
is(window.errors.length, expectedErrorCount, "expectedErrorCount should be " + expectedErrorCount);
is(window.errors[expectedErrorCount - 1], 'InvalidStateError', "Error name should be 'InvalidStateError'");
</script>
</body>
</html>

Просмотреть файл

@ -1,48 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=783129
-->
<head>
<title>Test for document.registerElement lifecycle callback</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script>
var p = Object.create(HTMLElement.prototype);
var createdCallbackCallCount = 0;
// By the time the base element queue is processed via the microtask,
// both x-hello elements should be in the document.
p.createdCallback = function() {
var one = document.getElementById("one");
var two = document.getElementById("two");
isnot(one, null, "First x-hello element should be in the tree.");
isnot(two, null, "Second x-hello element should be in the tree.");
createdCallbackCallCount++;
if (createdCallbackCallCount == 2) {
SimpleTest.finish();
}
if (createdCallbackCallCount > 2) {
ok(false, "Created callback called too much.");
}
};
p.attributeChangedCallback = function(name, oldValue, newValue) {
ok(false, "Attribute changed callback should not be called because callbacks should not be queued until created callback invoked.");
};
document.registerElement("x-hello", { prototype: p });
SimpleTest.waitForExplicitFinish();
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=783129">Bug 783129</a>
<x-hello id="one"></x-hello>
<x-hello id="two"></x-hello>
<script>
</script>
</body>
</html>

Просмотреть файл

@ -11,7 +11,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=783129
var extendedButtonProto = Object.create(HTMLButtonElement.prototype);
var buttonCallbackCalled = false;
extendedButtonProto.createdCallback = function() {
extendedButtonProto.connectedCallback = function() {
is(buttonCallbackCalled, false, "created callback for x-button should only be called once.");
is(this.tagName, "BUTTON", "Only the <button> element should be upgraded.");
buttonCallbackCalled = true;
@ -21,7 +21,7 @@ document.registerElement("x-button", { prototype: extendedButtonProto, extends:
var divProto = Object.create(HTMLDivElement.prototype);
var divCallbackCalled = false;
divProto.createdCallback = function() {
divProto.connectedCallback = function() {
is(divCallbackCalled, false, "created callback for x-div should only be called once.");
is(buttonCallbackCalled, true, "crated callback should be called for x-button before x-div.");
is(this.tagName, "X-DIV", "Only the <x-div> element should be upgraded.");

Просмотреть файл

@ -56,7 +56,11 @@ const char* const kFragHeader_Tex2DRect = "\
const char* const kFragHeader_TexExt = "\
#extension GL_OES_EGL_image_external : require \n\
#define SAMPLER samplerExternalOES \n\
#define TEXTURE texture2D \n\
#if __VERSION__ >= 130 \n\
#define TEXTURE texture \n\
#else \n\
#define TEXTURE texture2D \n\
#endif \n\
";
const char* const kFragBody_RGBA = "\
@ -71,14 +75,13 @@ const char* const kFragBody_RGBA = "\
const char* const kFragBody_CrYCb = "\
VARYING vec2 vTexCoord0; \n\
uniform SAMPLER uTex0; \n\
uniform mat4 uColorMatrix; \n\
uniform MAT4X3 uColorMatrix; \n\
\n\
void main(void) \n\
{ \n\
vec4 yuv = vec4(TEXTURE(uTex0, vTexCoord0).gbr, \n\
1.0); \n\
vec4 rgb = uColorMatrix * yuv; \n\
FRAG_COLOR = vec4(rgb.rgb, 1.0); \n\
FRAG_COLOR = vec4((uColorMatrix * yuv).rgb, 1.0); \n\
} \n\
";
const char* const kFragBody_NV12 = "\
@ -86,15 +89,14 @@ const char* const kFragBody_NV12 = "\
VARYING vec2 vTexCoord1; \n\
uniform SAMPLER uTex0; \n\
uniform SAMPLER uTex1; \n\
uniform mat4 uColorMatrix; \n\
uniform MAT4X3 uColorMatrix; \n\
\n\
void main(void) \n\
{ \n\
vec4 yuv = vec4(TEXTURE(uTex0, vTexCoord0).x, \n\
TEXTURE(uTex1, vTexCoord1).xy, \n\
1.0); \n\
vec4 rgb = uColorMatrix * yuv; \n\
FRAG_COLOR = vec4(rgb.rgb, 1.0); \n\
FRAG_COLOR = vec4((uColorMatrix * yuv).rgb, 1.0); \n\
} \n\
";
const char* const kFragBody_PlanarYUV = "\
@ -103,7 +105,7 @@ const char* const kFragBody_PlanarYUV = "\
uniform SAMPLER uTex0; \n\
uniform SAMPLER uTex1; \n\
uniform SAMPLER uTex2; \n\
uniform mat4 uColorMatrix; \n\
uniform MAT4X3 uColorMatrix; \n\
\n\
void main(void) \n\
{ \n\
@ -111,13 +113,88 @@ const char* const kFragBody_PlanarYUV = "\
TEXTURE(uTex1, vTexCoord1).x, \n\
TEXTURE(uTex2, vTexCoord1).x, \n\
1.0); \n\
vec4 rgb = uColorMatrix * yuv; \n\
FRAG_COLOR = vec4(rgb.rgb, 1.0); \n\
FRAG_COLOR = vec4((uColorMatrix * yuv).rgb, 1.0); \n\
} \n\
";
// --
template<uint8_t N>
/*static*/ Mat<N>
Mat<N>::Zero()
{
Mat<N> ret;
for (auto& x : ret.m) {
x = 0.0f;
}
return ret;
}
template<uint8_t N>
/*static*/ Mat<N>
Mat<N>::I()
{
auto ret = Mat<N>::Zero();
for (uint8_t i = 0; i < N; i++) {
ret.at(i,i) = 1.0f;
}
return ret;
}
template<uint8_t N>
Mat<N>
Mat<N>::operator*(const Mat<N>& r) const
{
Mat<N> ret;
for (uint8_t x = 0; x < N; x++) {
for (uint8_t y = 0; y < N; y++) {
float sum = 0.0f;
for (uint8_t i = 0; i < N; i++) {
sum += at(i,y) * r.at(x,i);
}
ret.at(x,y) = sum;
}
}
return ret;
}
Mat3
SubRectMat3(const float x, const float y, const float w, const float h)
{
auto ret = Mat3::Zero();
ret.at(0,0) = w;
ret.at(1,1) = h;
ret.at(2,0) = x;
ret.at(2,1) = y;
ret.at(2,2) = 1.0f;
return ret;
}
Mat3
SubRectMat3(const gfx::IntRect& subrect, const gfx::IntSize& size)
{
return SubRectMat3(float(subrect.x) / size.width,
float(subrect.y) / size.height,
float(subrect.width) / size.width,
float(subrect.height) / size.height);
}
Mat3
SubRectMat3(const gfx::IntRect& bigSubrect, const gfx::IntSize& smallSize,
const gfx::IntSize& divisors)
{
const float x = float(bigSubrect.x) / divisors.width;
const float y = float(bigSubrect.y) / divisors.height;
const float w = float(bigSubrect.width) / divisors.width;
const float h = float(bigSubrect.height) / divisors.height;
return SubRectMat3(x / smallSize.width,
y / smallSize.height,
w / smallSize.width,
h / smallSize.height);
}
// --
ScopedSaveMultiTex::ScopedSaveMultiTex(GLContext* const gl, const uint8_t texCount,
const GLenum texTarget)
: mGL(*gl)
@ -266,6 +343,7 @@ public:
mGL.fColorMask(true, true, true, true);
mGL.fGetIntegerv(LOCAL_GL_VIEWPORT, viewport);
MOZ_ASSERT(destSize.width && destSize.height);
mGL.fViewport(0, 0, destSize.width, destSize.height);
}
@ -294,19 +372,33 @@ public:
DrawBlitProg::DrawBlitProg(const GLBlitHelper* const parent, const GLuint prog)
: mParent(*parent)
, mProg(prog)
, mLoc_u1ForYFlip(mParent.mGL->fGetUniformLocation(mProg, "u1ForYFlip"))
, mLoc_uSrcRect(mParent.mGL->fGetUniformLocation(mProg, "uSrcRect"))
, mLoc_uTexSize0(mParent.mGL->fGetUniformLocation(mProg, "uTexSize0"))
, mLoc_uTexSize1(mParent.mGL->fGetUniformLocation(mProg, "uTexSize1"))
, mLoc_uDivisors(mParent.mGL->fGetUniformLocation(mProg, "uDivisors"))
, mLoc_uDestMatrix(mParent.mGL->fGetUniformLocation(mProg, "uDestMatrix"))
, mLoc_uTexMatrix0(mParent.mGL->fGetUniformLocation(mProg, "uTexMatrix0"))
, mLoc_uTexMatrix1(mParent.mGL->fGetUniformLocation(mProg, "uTexMatrix1"))
, mLoc_uColorMatrix(mParent.mGL->fGetUniformLocation(mProg, "uColorMatrix"))
, mType_uColorMatrix(0)
{
MOZ_ASSERT(mLoc_u1ForYFlip != -1);
MOZ_ASSERT(mLoc_uSrcRect != -1);
MOZ_ASSERT(mLoc_uTexSize0 != -1);
MOZ_ASSERT(mLoc_uDestMatrix != -1);
MOZ_ASSERT(mLoc_uTexMatrix0 != -1);
if (mLoc_uColorMatrix != -1) {
MOZ_ASSERT(mLoc_uTexSize1 != -1);
MOZ_ASSERT(mLoc_uDivisors != -1);
MOZ_ASSERT(mLoc_uTexMatrix1 != -1);
const auto& gl = mParent.mGL;
int32_t numActiveUniforms = 0;
gl->fGetProgramiv(mProg, LOCAL_GL_ACTIVE_UNIFORMS, &numActiveUniforms);
const size_t kMaxNameSize = 32;
char name[kMaxNameSize] = {0};
GLint size = 0;
GLenum type = 0;
for (int32_t i = 0; i < numActiveUniforms; i++) {
gl->fGetActiveUniform(mProg, i, kMaxNameSize, nullptr, &size, &type, name);
if (strcmp("uColorMatrix", name) == 0) {
mType_uColorMatrix = type;
break;
}
}
MOZ_ASSERT(mType_uColorMatrix);
}
}
@ -329,18 +421,49 @@ DrawBlitProg::Draw(const BaseArgs& args, const YUVArgs* const argsYUV) const
// --
gl->fUniform1f(mLoc_u1ForYFlip, args.yFlip ? 1 : 0);
gl->fUniform4f(mLoc_uSrcRect,
args.srcRect.x, args.srcRect.y,
args.srcRect.width, args.srcRect.height);
gl->fUniform2f(mLoc_uTexSize0, args.texSize0.width, args.texSize0.height);
Mat3 destMatrix;
if (args.destRect) {
const auto& destRect = args.destRect.value();
destMatrix = SubRectMat3(destRect.x / args.destSize.width,
destRect.y / args.destSize.height,
destRect.width / args.destSize.width,
destRect.height / args.destSize.height);
} else {
destMatrix = Mat3::I();
}
if (args.yFlip) {
// Apply the y-flip matrix before the destMatrix.
// That is, flip y=[0-1] to y=[1-0] before we restrict to the destRect.
destMatrix.at(2,1) += destMatrix.at(1,1);
destMatrix.at(1,1) *= -1.0f;
}
gl->fUniformMatrix3fv(mLoc_uDestMatrix, 1, false, destMatrix.m);
gl->fUniformMatrix3fv(mLoc_uTexMatrix0, 1, false, args.texMatrix0.m);
MOZ_ASSERT(bool(argsYUV) == (mLoc_uColorMatrix != -1));
if (argsYUV) {
gl->fUniform2f(mLoc_uTexSize1, argsYUV->texSize1.width, argsYUV->texSize1.height);
gl->fUniform2f(mLoc_uDivisors, argsYUV->divisors.width, argsYUV->divisors.height);
gl->fUniformMatrix3fv(mLoc_uTexMatrix1, 1, false, argsYUV->texMatrix1.m);
const auto& colorMatrix = gfxUtils::YuvToRgbMatrix4x4ColumnMajor(argsYUV->colorSpace);
gl->fUniformMatrix4fv(mLoc_uColorMatrix, 1, false, colorMatrix);
float mat4x3[4*3];
switch (mType_uColorMatrix) {
case LOCAL_GL_FLOAT_MAT4:
gl->fUniformMatrix4fv(mLoc_uColorMatrix, 1, false, colorMatrix);
break;
case LOCAL_GL_FLOAT_MAT4x3:
for (int x = 0; x < 4; x++) {
for (int y = 0; y < 3; y++) {
mat4x3[3*x+y] = colorMatrix[4*x+y];
}
}
gl->fUniformMatrix4x3fv(mLoc_uColorMatrix, 1, false, mat4x3);
break;
default:
gfxCriticalError() << "Bad mType_uColorMatrix: "
<< gfx::hexa(mType_uColorMatrix);
}
}
// --
@ -424,8 +547,12 @@ GLBlitHelper::GLBlitHelper(GLContext* const gl)
// --
if (!mGL->IsGLES()) {
const auto glslVersion = mGL->ShadingLanguageVersion();
const auto glslVersion = mGL->ShadingLanguageVersion();
if (mGL->IsGLES()) {
if (glslVersion >= 300) {
mDrawBlitProg_VersionLine = nsPrintfCString("#version %u es\n", glslVersion);
}
} else {
if (glslVersion >= 130) {
mDrawBlitProg_VersionLine = nsPrintfCString("#version %u\n", glslVersion);
}
@ -440,31 +567,24 @@ GLBlitHelper::GLBlitHelper(GLContext* const gl)
#define VARYING varying \n\
#endif \n\
\n\
ATTRIBUTE vec2 aVert; \n\
ATTRIBUTE vec2 aVert; // [0.0-1.0] \n\
\n\
uniform float u1ForYFlip; \n\
uniform vec4 uSrcRect; \n\
uniform vec2 uTexSize0; \n\
uniform vec2 uTexSize1; \n\
uniform vec2 uDivisors; \n\
uniform mat3 uDestMatrix; \n\
uniform mat3 uTexMatrix0; \n\
uniform mat3 uTexMatrix1; \n\
\n\
VARYING vec2 vTexCoord0; \n\
VARYING vec2 vTexCoord1; \n\
\n\
void main(void) \n\
{ \n\
vec2 vertPos = aVert * 2.0 - 1.0; \n\
gl_Position = vec4(vertPos, 0.0, 1.0); \n\
vec2 destPos = (uDestMatrix * vec3(aVert, 1.0)).xy; \n\
gl_Position = vec4(destPos * 2.0 - 1.0, 0.0, 1.0); \n\
\n\
vec2 texCoord = aVert; \n\
texCoord.y = abs(u1ForYFlip - texCoord.y); \n\
texCoord = texCoord * uSrcRect.zw + uSrcRect.xy; \n\
\n\
vTexCoord0 = texCoord / uTexSize0; \n\
vTexCoord1 = texCoord / (uTexSize1 * uDivisors); \n\
vTexCoord0 = (uTexMatrix0 * vec3(aVert, 1.0)).xy; \n\
vTexCoord1 = (uTexMatrix1 * vec3(aVert, 1.0)).xy; \n\
} \n\
";
const char* const parts[] = {
mDrawBlitProg_VersionLine.get(),
kVertSource
@ -506,7 +626,6 @@ GLBlitHelper::GetDrawBlitProg(const DrawBlitProg::Key& key) const
return pair.second;
}
const DrawBlitProg*
GLBlitHelper::CreateDrawBlitProg(const DrawBlitProg::Key& key) const
{
@ -522,11 +641,16 @@ GLBlitHelper::CreateDrawBlitProg(const DrawBlitProg::Key& key) const
#if __VERSION__ >= 130 \n\
#define VARYING in \n\
#define FRAG_COLOR oFragColor \n\
\n\
out vec4 FRAG_COLOR; \n\
#else \n\
#define VARYING varying \n\
#define FRAG_COLOR gl_FragColor \n\
#endif \n\
\n\
#if __VERSION__ >= 120 \n\
#define MAT4X3 mat4x3 \n\
#else \n\
#define MAT4X3 mat4 \n\
#endif \n\
";
@ -578,13 +702,13 @@ GLBlitHelper::CreateDrawBlitProg(const DrawBlitProg::Key& key) const
mGL->fGetShaderiv(vs, LOCAL_GL_INFO_LOG_LENGTH, (GLint*)&vsLogLen);
const UniquePtr<char[]> vsLog(new char[vsLogLen+1]);
mGL->fGetShaderInfoLog(vs, vsLogLen, nullptr, vsLog.get());
progLog[progLogLen] = 0;
vsLog[vsLogLen] = 0;
GLuint fsLogLen = 0;
mGL->fGetShaderiv(fs, LOCAL_GL_INFO_LOG_LENGTH, (GLint*)&fsLogLen);
const UniquePtr<char[]> fsLog(new char[fsLogLen+1]);
mGL->fGetShaderInfoLog(fs, fsLogLen, nullptr, fsLog.get());
progLog[progLogLen] = 0;
fsLog[fsLogLen] = 0;
gfxCriticalError() << "DrawBlitProg link failed:\n"
<< "progLog: " << progLog.get() << "\n"
@ -596,9 +720,9 @@ GLBlitHelper::CreateDrawBlitProg(const DrawBlitProg::Key& key) const
// -----------------------------------------------------------------------------
bool
GLBlitHelper::BlitImageToFramebuffer(layers::Image* srcImage,
GLBlitHelper::BlitImageToFramebuffer(layers::Image* const srcImage,
const gfx::IntSize& destSize,
OriginPos destOrigin)
const OriginPos destOrigin)
{
switch (srcImage->GetFormat()) {
case ImageFormat::PLANAR_YCBCR:
@ -618,8 +742,7 @@ GLBlitHelper::BlitImageToFramebuffer(layers::Image* srcImage,
return BlitImage(static_cast<layers::GPUVideoImage*>(srcImage), destSize,
destOrigin);
case ImageFormat::D3D11_YCBCR_IMAGE:
return BlitImage((layers::D3D11YCbCrImage*)srcImage, destSize,
destOrigin);
return BlitImage((layers::D3D11YCbCrImage*)srcImage, destSize, destOrigin);
case ImageFormat::D3D9_RGB32_TEXTURE:
return false; // todo
#endif
@ -774,14 +897,18 @@ GLBlitHelper::BlitImage(layers::PlanarYCbCrImage* const yuvImage,
// --
const auto& clipRect = yuvData->GetPictureRect();
const auto srcOrigin = OriginPos::BottomLeft;
const bool yFlip = (destOrigin != srcOrigin);
const auto& clipRect = yuvData->GetPictureRect();
const auto& colorSpace = yuvData->mYUVColorSpace;
const DrawBlitProg::BaseArgs baseArgs = { destSize, yFlip, clipRect, yTexSize };
const DrawBlitProg::YUVArgs yuvArgs = { uvTexSize, divisors, colorSpace };
const DrawBlitProg::BaseArgs baseArgs = {
SubRectMat3(clipRect, yTexSize),
yFlip, destSize, Nothing()
};
const DrawBlitProg::YUVArgs yuvArgs = {
SubRectMat3(clipRect, uvTexSize, divisors),
yuvData->mYUVColorSpace
};
prog->Draw(baseArgs, &yuvArgs);
return true;
}
@ -802,13 +929,14 @@ GLBlitHelper::BlitImage(layers::MacIOSurfaceImage* const srcImage,
const auto cglContext = glCGL->GetCGLContext();
const auto& srcOrigin = OriginPos::BottomLeft;
const bool yFlip = destOrigin != srcOrigin;
const gfx::IntRect clipRect({0, 0}, srcImage->GetSize());
const gfx::IntSize texRectNormFactor(1, 1);
const DrawBlitProg::BaseArgs baseArgs = { destSize, yFlip, clipRect,
texRectNormFactor };
DrawBlitProg::YUVArgs yuvArgs = { texRectNormFactor, {2,2}, YUVColorSpace::BT601 };
DrawBlitProg::BaseArgs baseArgs;
baseArgs.yFlip = (destOrigin != srcOrigin);
baseArgs.destSize = destSize;
DrawBlitProg::YUVArgs yuvArgs;
yuvArgs.colorSpace = YUVColorSpace::BT601;
const DrawBlitProg::YUVArgs* pYuvArgs = nullptr;
auto planes = iosurf->GetPlaneCount();
@ -918,6 +1046,11 @@ GLBlitHelper::BlitImage(layers::MacIOSurfaceImage* const srcImage,
gfxCriticalError() << errStr.get() << " (iosurf format: " << formatStr << ")";
return false;
}
if (p == 0) {
baseArgs.texMatrix0 = SubRectMat3(0, 0, width, height);
yuvArgs.texMatrix1 = SubRectMat3(0, 0, width / 2.0, height / 2.0);
}
}
const auto& prog = GetDrawBlitProg({fragHeader, fragBody});
@ -937,31 +1070,29 @@ GLBlitHelper::DrawBlitTextureToFramebuffer(const GLuint srcTex,
const gfx::IntSize& destSize,
const GLenum srcTarget) const
{
const gfx::IntRect clipRect(0, 0, srcSize.width, srcSize.height);
DrawBlitProg::Key key;
gfx::IntSize texSizeDivisor;
const char* fragHeader;
Mat3 texMatrix0;
switch (srcTarget) {
case LOCAL_GL_TEXTURE_2D:
key = {kFragHeader_Tex2D, kFragBody_RGBA};
texSizeDivisor = srcSize;
fragHeader = kFragHeader_Tex2D;
texMatrix0 = Mat3::I();
break;
case LOCAL_GL_TEXTURE_RECTANGLE_ARB:
key = {kFragHeader_Tex2DRect, kFragBody_RGBA};
texSizeDivisor = gfx::IntSize(1, 1);
fragHeader = kFragHeader_Tex2DRect;
texMatrix0 = SubRectMat3(0, 0, srcSize.width, srcSize.height);
break;
default:
gfxCriticalError() << "Unexpected srcTarget: " << srcTarget;
return;
}
const auto& prog = GetDrawBlitProg(key);
const auto& prog = GetDrawBlitProg({ fragHeader, kFragBody_RGBA});
MOZ_ASSERT(prog);
const ScopedSaveMultiTex saveTex(mGL, 1, srcTarget);
mGL->fBindTexture(srcTarget, srcTex);
const bool yFlip = false;
const DrawBlitProg::BaseArgs baseArgs = { destSize, yFlip, clipRect, texSizeDivisor };
const DrawBlitProg::BaseArgs baseArgs = { texMatrix0, yFlip, destSize, Nothing() };
prog->Draw(baseArgs);
}

Просмотреть файл

@ -41,21 +41,41 @@ bool
GuessDivisors(const gfx::IntSize& ySize, const gfx::IntSize& uvSize,
gfx::IntSize* const out_divisors);
template<uint8_t N>
struct Mat
{
float m[N*N]; // column-major, for GL
float& at(const uint8_t x, const uint8_t y) {
return m[N*x+y];
}
static Mat<N> Zero();
static Mat<N> I();
Mat<N> operator*(const Mat<N>& r) const;
};
typedef Mat<3> Mat3;
Mat3 SubRectMat3(float x, float y, float w, float h);
Mat3 SubRectMat3(const gfx::IntRect& subrect, const gfx::IntSize& size);
Mat3 SubRectMat3(const gfx::IntRect& bigSubrect, const gfx::IntSize& smallSize,
const gfx::IntSize& divisors);
class DrawBlitProg final
{
const GLBlitHelper& mParent;
const GLuint mProg;
const GLint mLoc_u1ForYFlip;
const GLint mLoc_uSrcRect;
const GLint mLoc_uTexSize0;
const GLint mLoc_uTexSize1;
const GLint mLoc_uDivisors;
const GLint mLoc_uDestMatrix;
const GLint mLoc_uTexMatrix0;
const GLint mLoc_uTexMatrix1;
const GLint mLoc_uColorMatrix;
GLenum mType_uColorMatrix;
public:
struct Key final {
const char* fragHeader;
const char* fragBody;
const char* const fragHeader;
const char* const fragBody;
bool operator <(const Key& x) const {
if (fragHeader != x.fragHeader)
@ -68,14 +88,13 @@ public:
~DrawBlitProg();
struct BaseArgs final {
gfx::IntSize destSize;
Mat3 texMatrix0;
bool yFlip;
gfx::IntRect srcRect;
gfx::IntSize texSize0;
gfx::IntSize destSize; // Always needed for (at least) setting the viewport.
Maybe<gfx::IntRect> destRect;
};
struct YUVArgs final {
gfx::IntSize texSize1;
gfx::IntSize divisors;
Mat3 texMatrix1;
YUVColorSpace colorSpace;
};
@ -181,8 +200,8 @@ private:
bool BlitAngleYCbCr(const WindowsHandle (&handleList)[3],
const gfx::IntRect& clipRect,
const gfx::IntSize& ySize, const gfx::IntSize& uvSize,
const YUVColorSpace colorSpace,
const gfx::IntSize& destSize, OriginPos destOrigin) const;
const YUVColorSpace colorSpace, const gfx::IntSize& destSize,
OriginPos destOrigin) const;
bool BlitAnglePlanes(uint8_t numPlanes, const RefPtr<ID3D11Texture2D>* texD3DList,
const DrawBlitProg* prog, const DrawBlitProg::BaseArgs& baseArgs,

Просмотреть файл

@ -20,8 +20,7 @@ namespace mozilla {
namespace gl {
static EGLStreamKHR
StreamFromD3DTexture(ID3D11Texture2D* const texD3D,
const EGLAttrib* const postAttribs)
StreamFromD3DTexture(ID3D11Texture2D* const texD3D, const EGLAttrib* const postAttribs)
{
auto& egl = sEGLLibrary;
if (!egl.IsExtensionSupported(GLLibraryEGL::NV_stream_consumer_gltexture_yuv) ||
@ -244,7 +243,8 @@ GLBlitHelper::BlitImage(layers::D3D11YCbCrImage* const srcImage,
bool
GLBlitHelper::BlitDescriptor(const layers::SurfaceDescriptorD3D10& desc,
const gfx::IntSize& destSize, OriginPos destOrigin) const
const gfx::IntSize& destSize,
const OriginPos destOrigin) const
{
const auto& d3d = GetD3D11();
if (!d3d)
@ -295,8 +295,14 @@ GLBlitHelper::BlitDescriptor(const layers::SurfaceDescriptorD3D10& desc,
ySize.height / divisors.height);
const bool yFlip = destOrigin != srcOrigin;
const DrawBlitProg::BaseArgs baseArgs = { destSize, yFlip, clipRect, ySize };
const DrawBlitProg::YUVArgs yuvArgs = { uvSize, divisors, colorSpace };
const DrawBlitProg::BaseArgs baseArgs = {
SubRectMat3(clipRect, ySize),
yFlip, destSize, Nothing()
};
const DrawBlitProg::YUVArgs yuvArgs = {
SubRectMat3(clipRect, uvSize, divisors),
colorSpace
};
const auto& prog = GetDrawBlitProg({kFragHeader_TexExt, kFragBody_NV12});
MOZ_RELEASE_ASSERT(prog);
@ -310,8 +316,8 @@ bool
GLBlitHelper::BlitAngleYCbCr(const WindowsHandle (&handleList)[3],
const gfx::IntRect& clipRect,
const gfx::IntSize& ySize, const gfx::IntSize& uvSize,
const YUVColorSpace colorSpace,
const gfx::IntSize& destSize, OriginPos destOrigin) const
const YUVColorSpace colorSpace, const gfx::IntSize& destSize,
const OriginPos destOrigin) const
{
const auto& d3d = GetD3D11();
if (!d3d)
@ -331,8 +337,14 @@ GLBlitHelper::BlitAngleYCbCr(const WindowsHandle (&handleList)[3],
const BindAnglePlanes bindPlanes(this, 3, texList);
const bool yFlip = destOrigin != srcOrigin;
const DrawBlitProg::BaseArgs baseArgs = { destSize, yFlip, clipRect, ySize };
const DrawBlitProg::YUVArgs yuvArgs = { uvSize, divisors, colorSpace };
const DrawBlitProg::BaseArgs baseArgs = {
SubRectMat3(clipRect, ySize),
yFlip, destSize, Nothing()
};
const DrawBlitProg::YUVArgs yuvArgs = {
SubRectMat3(clipRect, uvSize, divisors),
colorSpace
};
const auto& prog = GetDrawBlitProg({kFragHeader_TexExt, kFragBody_PlanarYUV});
MOZ_RELEASE_ASSERT(prog);

Просмотреть файл

@ -144,7 +144,7 @@ nsFontCache::GetMetricsFor(const nsFont& aFont,
RefPtr<nsFontMetrics> fm = new nsFontMetrics(aFont, params, mContext);
// the mFontMetrics list has the "head" at the end, because append
// is cheaper than insert
mFontMetrics.AppendElement(do_AddRef(fm.get()).take());
mFontMetrics.AppendElement(do_AddRef(fm).take());
return fm.forget();
}

Просмотреть файл

@ -15,11 +15,13 @@
namespace mozilla {
namespace mscom {
struct IInterceptor;
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 GetHandlerPayloadSize(NotNull<IInterceptor*> aInterceptor, NotNull<DWORD*> aOutPayloadSize) = 0;
virtual STDMETHODIMP WriteHandlerPayload(NotNull<IInterceptor*> aInterceptor, NotNull<IStream*> aStream) = 0;
virtual STDMETHODIMP_(REFIID) MarshalAs(REFIID aIid) = 0;
};

Просмотреть файл

@ -247,7 +247,8 @@ Interceptor::GetMarshalSizeMax(REFIID riid, void* pv, DWORD dwDestContext,
}
DWORD payloadSize = 0;
hr = mEventSink->GetHandlerPayloadSize(WrapNotNull(&payloadSize));
hr = mEventSink->GetHandlerPayloadSize(WrapNotNull(this),
WrapNotNull(&payloadSize));
if (hr == E_NOTIMPL) {
return S_OK;
}
@ -307,7 +308,7 @@ Interceptor::MarshalInterface(IStream* pStm, REFIID riid, void* pv,
}
#endif // defined(MOZ_MSCOM_REMARSHAL_NO_HANDLER)
hr = mEventSink->WriteHandlerPayload(WrapNotNull(pStm));
hr = mEventSink->WriteHandlerPayload(WrapNotNull(this), WrapNotNull(pStm));
if (hr == E_NOTIMPL) {
return S_OK;
}

Просмотреть файл

@ -517,21 +517,23 @@ MainThreadHandoff::GetHandler(NotNull<CLSID*> aHandlerClsid)
}
HRESULT
MainThreadHandoff::GetHandlerPayloadSize(NotNull<DWORD*> aOutPayloadSize)
MainThreadHandoff::GetHandlerPayloadSize(NotNull<IInterceptor*> aInterceptor,
NotNull<DWORD*> aOutPayloadSize)
{
if (!mHandlerProvider) {
return E_NOTIMPL;
}
return mHandlerProvider->GetHandlerPayloadSize(aOutPayloadSize);
return mHandlerProvider->GetHandlerPayloadSize(aInterceptor, aOutPayloadSize);
}
HRESULT
MainThreadHandoff::WriteHandlerPayload(NotNull<IStream*> aStream)
MainThreadHandoff::WriteHandlerPayload(NotNull<IInterceptor*> aInterceptor,
NotNull<IStream*> aStream)
{
if (!mHandlerProvider) {
return E_NOTIMPL;
}
return mHandlerProvider->WriteHandlerPayload(aStream);
return mHandlerProvider->WriteHandlerPayload(aInterceptor, aStream);
}
REFIID

Просмотреть файл

@ -61,8 +61,10 @@ public:
// IInterceptorSink
STDMETHODIMP SetInterceptor(IWeakReference* aInterceptor) override;
STDMETHODIMP GetHandler(NotNull<CLSID*> aHandlerClsid) override;
STDMETHODIMP GetHandlerPayloadSize(NotNull<DWORD*> aOutPayloadSize) override;
STDMETHODIMP WriteHandlerPayload(NotNull<IStream*> aStream) override;
STDMETHODIMP GetHandlerPayloadSize(NotNull<IInterceptor*> aInterceptor,
NotNull<DWORD*> aOutPayloadSize) override;
STDMETHODIMP WriteHandlerPayload(NotNull<IInterceptor*> aInterceptor,
NotNull<IStream*> aStream) override;
STDMETHODIMP_(REFIID) MarshalAs(REFIID aIid) override;
// ICallFrameWalker

Просмотреть файл

@ -42,6 +42,14 @@ const size_t CellAlignMask = CellAlignBytes - 1;
const size_t CellBytesPerMarkBit = CellAlignBytes;
/*
* We sometimes use an index to refer to a cell in an arena. The index for a
* cell is found by dividing by the cell alignment so not all indicies refer to
* valid cells.
*/
const size_t ArenaCellIndexBytes = CellAlignBytes;
const size_t MaxArenaCellIndex = ArenaSize / CellAlignBytes;
/* These are magic constants derived from actual offsets in gc/Heap.h. */
#ifdef JS_GC_SMALL_CHUNK_SIZE
const size_t ChunkMarkBitmapOffset = 258104;

Просмотреть файл

@ -24,9 +24,9 @@ namespace JS {
_(GetProp_Unboxed) \
_(GetProp_CommonGetter) \
_(GetProp_InlineAccess) \
_(GetProp_InlineProtoAccess) \
_(GetProp_Innerize) \
_(GetProp_InlineCache) \
_(GetProp_SharedCache) \
_(GetProp_ModuleNamespace) \
\
_(SetProp_CommonSetter) \

Просмотреть файл

@ -19,7 +19,6 @@
#include "jsapi.h"
#include "jscntxt.h"
#include "jsfriendapi.h"
#include "jsgc.h"
#include "jsiter.h"
#include "jsobj.h"
#include "jsprf.h"

Просмотреть файл

@ -8,6 +8,7 @@
#include "jscntxt.h"
#include "gc/ArenaList.h"
#include "gc/GCInternals.h"
#include "gc/GCTrace.h"
#include "gc/Nursery.h"
@ -297,7 +298,7 @@ GCRuntime::refillFreeListFromActiveCooperatingThread(JSContext* cx, AllocKind th
Zone *zone = cx->zone();
MOZ_ASSERT(!JS::CurrentThreadIsHeapBusy(), "allocating while under GC");
return cx->arenas()->allocateFromArena(zone, thingKind, CheckThresholds);
return cx->arenas()->allocateFromArena(zone, thingKind, ShouldCheckThresholds::CheckThresholds);
}
/* static */ TenuredCell*
@ -308,7 +309,7 @@ GCRuntime::refillFreeListFromHelperThread(JSContext* cx, AllocKind thingKind)
Zone* zone = cx->zone();
MOZ_ASSERT(!zone->wasGCStarted());
return cx->arenas()->allocateFromArena(zone, thingKind, CheckThresholds);
return cx->arenas()->allocateFromArena(zone, thingKind, ShouldCheckThresholds::CheckThresholds);
}
/* static */ TenuredCell*
@ -323,7 +324,7 @@ GCRuntime::refillFreeListInGC(Zone* zone, AllocKind thingKind)
MOZ_ASSERT(JS::CurrentThreadIsHeapCollecting());
MOZ_ASSERT_IF(!JS::CurrentThreadIsHeapMinorCollecting(), !rt->gc.isBackgroundSweeping());
return zone->arenas.allocateFromArena(zone, thingKind, DontCheckThresholds);
return zone->arenas.allocateFromArena(zone, thingKind, ShouldCheckThresholds::DontCheckThresholds);
}
TenuredCell*
@ -415,15 +416,16 @@ GCRuntime::allocateArena(Chunk* chunk, Zone* zone, AllocKind thingKind,
MOZ_ASSERT(chunk->hasAvailableArenas());
// Fail the allocation if we are over our heap size limits.
if (checkThresholds && usage.gcBytes() >= tunables.gcMaxBytes())
if ((checkThresholds != ShouldCheckThresholds::DontCheckThresholds) &&
(usage.gcBytes() >= tunables.gcMaxBytes()))
return nullptr;
Arena* arena = chunk->allocateArena(rt, zone, thingKind, lock);
zone->usage.addGCArena();
// Trigger an incremental slice if needed.
if (checkThresholds)
maybeAllocTriggerGC(zone, lock);
if (checkThresholds != ShouldCheckThresholds::DontCheckThresholds)
maybeAllocTriggerZoneGC(zone, lock);
return arena;
}

544
js/src/gc/ArenaList.h Normal file
Просмотреть файл

@ -0,0 +1,544 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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 gc_ArenaList_h
#define gc_ArenaList_h
#include "gc/Heap.h"
#include "js/SliceBudget.h"
#include "threading/ProtectedData.h"
namespace JS {
struct Zone;
} /* namespace JS */
namespace js {
class Nursery;
class TenuringTracer;
namespace gc {
struct FinalizePhase;
/*
* A single segment of a SortedArenaList. Each segment has a head and a tail,
* which track the start and end of a segment for O(1) append and concatenation.
*/
struct SortedArenaListSegment
{
Arena* head;
Arena** tailp;
void clear() {
head = nullptr;
tailp = &head;
}
bool isEmpty() const {
return tailp == &head;
}
// Appends |arena| to this segment.
void append(Arena* arena) {
MOZ_ASSERT(arena);
MOZ_ASSERT_IF(head, head->getAllocKind() == arena->getAllocKind());
*tailp = arena;
tailp = &arena->next;
}
// Points the tail of this segment at |arena|, which may be null. Note
// that this does not change the tail itself, but merely which arena
// follows it. This essentially turns the tail into a cursor (see also the
// description of ArenaList), but from the perspective of a SortedArenaList
// this makes no difference.
void linkTo(Arena* arena) {
*tailp = arena;
}
};
/*
* Arena lists have a head and a cursor. The cursor conceptually lies on arena
* boundaries, i.e. before the first arena, between two arenas, or after the
* last arena.
*
* Arenas are usually sorted in order of increasing free space, with the cursor
* following the Arena currently being allocated from. This ordering should not
* be treated as an invariant, however, as the free lists may be cleared,
* leaving arenas previously used for allocation partially full. Sorting order
* is restored during sweeping.
* Arenas following the cursor should not be full.
*/
class ArenaList {
// The cursor is implemented via an indirect pointer, |cursorp_|, to allow
// for efficient list insertion at the cursor point and other list
// manipulations.
//
// - If the list is empty: |head| is null, |cursorp_| points to |head|, and
// therefore |*cursorp_| is null.
//
// - If the list is not empty: |head| is non-null, and...
//
// - If the cursor is at the start of the list: |cursorp_| points to
// |head|, and therefore |*cursorp_| points to the first arena.
//
// - If cursor is at the end of the list: |cursorp_| points to the |next|
// field of the last arena, and therefore |*cursorp_| is null.
//
// - If the cursor is at neither the start nor the end of the list:
// |cursorp_| points to the |next| field of the arena preceding the
// cursor, and therefore |*cursorp_| points to the arena following the
// cursor.
//
// |cursorp_| is never null.
//
Arena* head_;
Arena** cursorp_;
void copy(const ArenaList& other) {
other.check();
head_ = other.head_;
cursorp_ = other.isCursorAtHead() ? &head_ : other.cursorp_;
check();
}
public:
ArenaList() {
clear();
}
ArenaList(const ArenaList& other) {
copy(other);
}
ArenaList& operator=(const ArenaList& other) {
copy(other);
return *this;
}
explicit ArenaList(const SortedArenaListSegment& segment) {
head_ = segment.head;
cursorp_ = segment.isEmpty() ? &head_ : segment.tailp;
check();
}
// This does checking just of |head_| and |cursorp_|.
void check() const {
#ifdef DEBUG
// If the list is empty, it must have this form.
MOZ_ASSERT_IF(!head_, cursorp_ == &head_);
// If there's an arena following the cursor, it must not be full.
Arena* cursor = *cursorp_;
MOZ_ASSERT_IF(cursor, cursor->hasFreeThings());
#endif
}
void clear() {
head_ = nullptr;
cursorp_ = &head_;
check();
}
ArenaList copyAndClear() {
ArenaList result = *this;
clear();
return result;
}
bool isEmpty() const {
check();
return !head_;
}
// This returns nullptr if the list is empty.
Arena* head() const {
check();
return head_;
}
bool isCursorAtHead() const {
check();
return cursorp_ == &head_;
}
bool isCursorAtEnd() const {
check();
return !*cursorp_;
}
void moveCursorToEnd() {
while (!isCursorAtEnd())
cursorp_ = &(*cursorp_)->next;
}
// This can return nullptr.
Arena* arenaAfterCursor() const {
check();
return *cursorp_;
}
// This returns the arena after the cursor and moves the cursor past it.
Arena* takeNextArena() {
check();
Arena* arena = *cursorp_;
if (!arena)
return nullptr;
cursorp_ = &arena->next;
check();
return arena;
}
// This does two things.
// - Inserts |a| at the cursor.
// - Leaves the cursor sitting just before |a|, if |a| is not full, or just
// after |a|, if |a| is full.
void insertAtCursor(Arena* a) {
check();
a->next = *cursorp_;
*cursorp_ = a;
// At this point, the cursor is sitting before |a|. Move it after |a|
// if necessary.
if (!a->hasFreeThings())
cursorp_ = &a->next;
check();
}
// Inserts |a| at the cursor, then moves the cursor past it.
void insertBeforeCursor(Arena* a) {
check();
a->next = *cursorp_;
*cursorp_ = a;
cursorp_ = &a->next;
check();
}
// This inserts |other|, which must be full, at the cursor of |this|.
ArenaList& insertListWithCursorAtEnd(const ArenaList& other) {
check();
other.check();
MOZ_ASSERT(other.isCursorAtEnd());
if (other.isCursorAtHead())
return *this;
// Insert the full arenas of |other| after those of |this|.
*other.cursorp_ = *cursorp_;
*cursorp_ = other.head_;
cursorp_ = other.cursorp_;
check();
return *this;
}
Arena* removeRemainingArenas(Arena** arenap);
Arena** pickArenasToRelocate(size_t& arenaTotalOut, size_t& relocTotalOut);
Arena* relocateArenas(Arena* toRelocate, Arena* relocated,
js::SliceBudget& sliceBudget, gcstats::Statistics& stats);
};
/*
* A class that holds arenas in sorted order by appending arenas to specific
* segments. Each segment has a head and a tail, which can be linked up to
* other segments to create a contiguous ArenaList.
*/
class SortedArenaList
{
public:
// The minimum size, in bytes, of a GC thing.
static const size_t MinThingSize = 16;
static_assert(ArenaSize <= 4096, "When increasing the Arena size, please consider how"\
" this will affect the size of a SortedArenaList.");
static_assert(MinThingSize >= 16, "When decreasing the minimum thing size, please consider"\
" how this will affect the size of a SortedArenaList.");
private:
// The maximum number of GC things that an arena can hold.
static const size_t MaxThingsPerArena = (ArenaSize - ArenaHeaderSize) / MinThingSize;
size_t thingsPerArena_;
SortedArenaListSegment segments[MaxThingsPerArena + 1];
// Convenience functions to get the nth head and tail.
Arena* headAt(size_t n) { return segments[n].head; }
Arena** tailAt(size_t n) { return segments[n].tailp; }
public:
explicit SortedArenaList(size_t thingsPerArena = MaxThingsPerArena) {
reset(thingsPerArena);
}
void setThingsPerArena(size_t thingsPerArena) {
MOZ_ASSERT(thingsPerArena && thingsPerArena <= MaxThingsPerArena);
thingsPerArena_ = thingsPerArena;
}
// Resets the first |thingsPerArena| segments of this list for further use.
void reset(size_t thingsPerArena = MaxThingsPerArena) {
setThingsPerArena(thingsPerArena);
// Initialize the segments.
for (size_t i = 0; i <= thingsPerArena; ++i)
segments[i].clear();
}
// Inserts an arena, which has room for |nfree| more things, in its segment.
void insertAt(Arena* arena, size_t nfree) {
MOZ_ASSERT(nfree <= thingsPerArena_);
segments[nfree].append(arena);
}
// Remove all empty arenas, inserting them as a linked list.
void extractEmpty(Arena** empty) {
SortedArenaListSegment& segment = segments[thingsPerArena_];
if (segment.head) {
*segment.tailp = *empty;
*empty = segment.head;
segment.clear();
}
}
// Links up the tail of each non-empty segment to the head of the next
// non-empty segment, creating a contiguous list that is returned as an
// ArenaList. This is not a destructive operation: neither the head nor tail
// of any segment is modified. However, note that the Arenas in the
// resulting ArenaList should be treated as read-only unless the
// SortedArenaList is no longer needed: inserting or removing arenas would
// invalidate the SortedArenaList.
ArenaList toArenaList() {
// Link the non-empty segment tails up to the non-empty segment heads.
size_t tailIndex = 0;
for (size_t headIndex = 1; headIndex <= thingsPerArena_; ++headIndex) {
if (headAt(headIndex)) {
segments[tailIndex].linkTo(headAt(headIndex));
tailIndex = headIndex;
}
}
// Point the tail of the final non-empty segment at null. Note that if
// the list is empty, this will just set segments[0].head to null.
segments[tailIndex].linkTo(nullptr);
// Create an ArenaList with head and cursor set to the head and tail of
// the first segment (if that segment is empty, only the head is used).
return ArenaList(segments[0]);
}
};
enum class ShouldCheckThresholds
{
DontCheckThresholds = 0,
CheckThresholds = 1
};
class ArenaLists
{
JSRuntime* const runtime_;
/*
* For each arena kind its free list is represented as the first span with
* free things. Initially all the spans are initialized as empty. After we
* find a new arena with available things we move its first free span into
* the list and set the arena as fully allocated. way we do not need to
* update the arena after the initial allocation. When starting the
* GC we only move the head of the of the list of spans back to the arena
* only for the arena that was not fully allocated.
*/
ZoneGroupData<AllAllocKindArray<FreeSpan*>> freeLists_;
FreeSpan*& freeLists(AllocKind i) { return freeLists_.ref()[i]; }
FreeSpan* freeLists(AllocKind i) const { return freeLists_.ref()[i]; }
// Because the JITs can allocate from the free lists, they cannot be null.
// We use a placeholder FreeSpan that is empty (and wihout an associated
// Arena) so the JITs can fall back gracefully.
static FreeSpan placeholder;
ZoneGroupOrGCTaskData<AllAllocKindArray<ArenaList>> arenaLists_;
ArenaList& arenaLists(AllocKind i) { return arenaLists_.ref()[i]; }
const ArenaList& arenaLists(AllocKind i) const { return arenaLists_.ref()[i]; }
enum BackgroundFinalizeStateEnum { BFS_DONE, BFS_RUN };
typedef mozilla::Atomic<BackgroundFinalizeStateEnum, mozilla::SequentiallyConsistent>
BackgroundFinalizeState;
/* The current background finalization state, accessed atomically. */
UnprotectedData<AllAllocKindArray<BackgroundFinalizeState>> backgroundFinalizeState_;
BackgroundFinalizeState& backgroundFinalizeState(AllocKind i) { return backgroundFinalizeState_.ref()[i]; }
const BackgroundFinalizeState& backgroundFinalizeState(AllocKind i) const { return backgroundFinalizeState_.ref()[i]; }
/* For each arena kind, a list of arenas remaining to be swept. */
ActiveThreadOrGCTaskData<AllAllocKindArray<Arena*>> arenaListsToSweep_;
Arena*& arenaListsToSweep(AllocKind i) { return arenaListsToSweep_.ref()[i]; }
Arena* arenaListsToSweep(AllocKind i) const { return arenaListsToSweep_.ref()[i]; }
/* During incremental sweeping, a list of the arenas already swept. */
ZoneGroupOrGCTaskData<AllocKind> incrementalSweptArenaKind;
ZoneGroupOrGCTaskData<ArenaList> incrementalSweptArenas;
// Arena lists which have yet to be swept, but need additional foreground
// processing before they are swept.
ZoneGroupData<Arena*> gcShapeArenasToUpdate;
ZoneGroupData<Arena*> gcAccessorShapeArenasToUpdate;
ZoneGroupData<Arena*> gcScriptArenasToUpdate;
ZoneGroupData<Arena*> gcObjectGroupArenasToUpdate;
// While sweeping type information, these lists save the arenas for the
// objects which have already been finalized in the foreground (which must
// happen at the beginning of the GC), so that type sweeping can determine
// which of the object pointers are marked.
ZoneGroupData<ObjectAllocKindArray<ArenaList>> savedObjectArenas_;
ArenaList& savedObjectArenas(AllocKind i) { return savedObjectArenas_.ref()[i]; }
ZoneGroupData<Arena*> savedEmptyObjectArenas;
public:
explicit ArenaLists(JSRuntime* rt, ZoneGroup* group);
~ArenaLists();
const void* addressOfFreeList(AllocKind thingKind) const {
return reinterpret_cast<const void*>(&freeLists_.refNoCheck()[thingKind]);
}
Arena* getFirstArena(AllocKind thingKind) const {
return arenaLists(thingKind).head();
}
Arena* getFirstArenaToSweep(AllocKind thingKind) const {
return arenaListsToSweep(thingKind);
}
Arena* getFirstSweptArena(AllocKind thingKind) const {
if (thingKind != incrementalSweptArenaKind.ref())
return nullptr;
return incrementalSweptArenas.ref().head();
}
Arena* getArenaAfterCursor(AllocKind thingKind) const {
return arenaLists(thingKind).arenaAfterCursor();
}
bool arenaListsAreEmpty() const {
for (auto i : AllAllocKinds()) {
/*
* The arena cannot be empty if the background finalization is not yet
* done.
*/
if (backgroundFinalizeState(i) != BFS_DONE)
return false;
if (!arenaLists(i).isEmpty())
return false;
}
return true;
}
void unmarkAll() {
for (auto i : AllAllocKinds()) {
/* The background finalization must have stopped at this point. */
MOZ_ASSERT(backgroundFinalizeState(i) == BFS_DONE);
for (Arena* arena = arenaLists(i).head(); arena; arena = arena->next)
arena->unmarkAll();
}
}
bool doneBackgroundFinalize(AllocKind kind) const {
return backgroundFinalizeState(kind) == BFS_DONE;
}
bool needBackgroundFinalizeWait(AllocKind kind) const {
return backgroundFinalizeState(kind) != BFS_DONE;
}
/*
* Clear the free lists so we won't try to allocate from swept arenas.
*/
void purge() {
for (auto i : AllAllocKinds())
freeLists(i) = &placeholder;
}
inline void prepareForIncrementalGC();
/* Check if this arena is in use. */
bool arenaIsInUse(Arena* arena, AllocKind kind) const {
MOZ_ASSERT(arena);
return arena == freeLists(kind)->getArenaUnchecked();
}
MOZ_ALWAYS_INLINE TenuredCell* allocateFromFreeList(AllocKind thingKind, size_t thingSize) {
return freeLists(thingKind)->allocate(thingSize);
}
/*
* Moves all arenas from |fromArenaLists| into |this|.
*/
void adoptArenas(JSRuntime* runtime, ArenaLists* fromArenaLists, bool targetZoneIsCollecting);
/* True if the Arena in question is found in this ArenaLists */
bool containsArena(JSRuntime* runtime, Arena* arena);
void checkEmptyFreeLists() {
#ifdef DEBUG
for (auto i : AllAllocKinds())
checkEmptyFreeList(i);
#endif
}
bool checkEmptyArenaLists() {
bool empty = true;
#ifdef DEBUG
for (auto i : AllAllocKinds()) {
if (!checkEmptyArenaList(i))
empty = false;
}
#endif
return empty;
}
void checkEmptyFreeList(AllocKind kind) {
MOZ_ASSERT(freeLists(kind)->isEmpty());
}
bool checkEmptyArenaList(AllocKind kind);
bool relocateArenas(JS::Zone* zone, Arena*& relocatedListOut, JS::gcreason::Reason reason,
js::SliceBudget& sliceBudget, gcstats::Statistics& stats);
void queueForegroundObjectsForSweep(FreeOp* fop);
void queueForegroundThingsForSweep(FreeOp* fop);
void mergeForegroundSweptObjectArenas();
bool foregroundFinalize(FreeOp* fop, AllocKind thingKind, js::SliceBudget& sliceBudget,
SortedArenaList& sweepList);
static void backgroundFinalize(FreeOp* fop, Arena* listHead, Arena** empty);
// When finalizing arenas, whether to keep empty arenas on the list or
// release them immediately.
enum KeepArenasEnum {
RELEASE_ARENAS,
KEEP_ARENAS
};
private:
inline void queueForForegroundSweep(FreeOp* fop, const FinalizePhase& phase);
inline void queueForBackgroundSweep(FreeOp* fop, const FinalizePhase& phase);
inline void queueForForegroundSweep(FreeOp* fop, AllocKind thingKind);
inline void queueForBackgroundSweep(FreeOp* fop, AllocKind thingKind);
inline void mergeSweptArenas(AllocKind thingKind);
TenuredCell* allocateFromArena(JS::Zone* zone, AllocKind thingKind,
ShouldCheckThresholds checkThresholds);
inline TenuredCell* allocateFromArenaInner(JS::Zone* zone, Arena* arena, AllocKind kind);
friend class GCRuntime;
friend class js::Nursery;
friend class js::TenuringTracer;
};
} /* namespace gc */
} /* namespace js */
#endif /* gc_ArenaList_h */

Просмотреть файл

@ -9,13 +9,14 @@
#include "NamespaceImports.h"
#include "ds/Bitmap.h"
#include "gc/Heap.h"
#include "threading/ProtectedData.h"
#include "vm/Symbol.h"
namespace js {
namespace gc {
class Arena;
// This class manages state used for marking atoms during GCs.
// See AtomMarking.cpp for details.
class AtomMarkingRuntime

Просмотреть файл

@ -9,7 +9,7 @@
#include "NamespaceImports.h"
#include "gc/Heap.h"
#include "gc/Cell.h"
#include "gc/StoreBuffer.h"
#include "js/HeapAPI.h"
#include "js/Id.h"

412
js/src/gc/Cell.h Normal file
Просмотреть файл

@ -0,0 +1,412 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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 gc_Cell_h
#define gc_Cell_h
#include "gc/GCEnum.h"
#include "gc/Heap.h"
#include "js/GCAnnotations.h"
namespace JS {
namespace shadow {
struct Zone;
} /* namespace shadow */
enum class TraceKind;
struct Zone;
} /* namespace JS */
namespace js {
class GenericPrinter;
extern bool
RuntimeFromActiveCooperatingThreadIsHeapMajorCollecting(JS::shadow::Zone* shadowZone);
#ifdef DEBUG
// Barriers can't be triggered during backend Ion compilation, which may run on
// a helper thread.
extern bool
CurrentThreadIsIonCompiling();
#endif
extern void
TraceManuallyBarrieredGenericPointerEdge(JSTracer* trc, gc::Cell** thingp, const char* name);
namespace gc {
class Arena;
enum class AllocKind;
struct Chunk;
class TenuredCell;
// A GC cell is the base class for all GC things.
struct Cell
{
public:
MOZ_ALWAYS_INLINE bool isTenured() const { return !IsInsideNursery(this); }
MOZ_ALWAYS_INLINE const TenuredCell& asTenured() const;
MOZ_ALWAYS_INLINE TenuredCell& asTenured();
MOZ_ALWAYS_INLINE bool isMarkedAny() const;
MOZ_ALWAYS_INLINE bool isMarkedBlack() const;
MOZ_ALWAYS_INLINE bool isMarkedGray() const;
inline JSRuntime* runtimeFromActiveCooperatingThread() const;
// Note: Unrestricted access to the runtime of a GC thing from an arbitrary
// thread can easily lead to races. Use this method very carefully.
inline JSRuntime* runtimeFromAnyThread() const;
// May be overridden by GC thing kinds that have a compartment pointer.
inline JSCompartment* maybeCompartment() const { return nullptr; }
// The StoreBuffer used to record incoming pointers from the tenured heap.
// This will return nullptr for a tenured cell.
inline StoreBuffer* storeBuffer() const;
inline JS::TraceKind getTraceKind() const;
static MOZ_ALWAYS_INLINE bool needWriteBarrierPre(JS::Zone* zone);
#ifdef DEBUG
inline bool isAligned() const;
void dump(GenericPrinter& out) const;
void dump() const;
#endif
protected:
uintptr_t address() const;
inline Chunk* chunk() const;
} JS_HAZ_GC_THING;
// A GC TenuredCell gets behaviors that are valid for things in the Tenured
// heap, such as access to the arena and mark bits.
class TenuredCell : public Cell
{
public:
// Construct a TenuredCell from a void*, making various sanity assertions.
static MOZ_ALWAYS_INLINE TenuredCell* fromPointer(void* ptr);
static MOZ_ALWAYS_INLINE const TenuredCell* fromPointer(const void* ptr);
// Mark bit management.
MOZ_ALWAYS_INLINE bool isMarkedAny() const;
MOZ_ALWAYS_INLINE bool isMarkedBlack() const;
MOZ_ALWAYS_INLINE bool isMarkedGray() const;
// The return value indicates if the cell went from unmarked to marked.
MOZ_ALWAYS_INLINE bool markIfUnmarked(MarkColor color = MarkColor::Black) const;
MOZ_ALWAYS_INLINE void markBlack() const;
MOZ_ALWAYS_INLINE void copyMarkBitsFrom(const TenuredCell* src);
// Access to the arena.
inline Arena* arena() const;
inline AllocKind getAllocKind() const;
inline JS::TraceKind getTraceKind() const;
inline JS::Zone* zone() const;
inline JS::Zone* zoneFromAnyThread() const;
inline bool isInsideZone(JS::Zone* zone) const;
MOZ_ALWAYS_INLINE JS::shadow::Zone* shadowZone() const {
return JS::shadow::Zone::asShadowZone(zone());
}
MOZ_ALWAYS_INLINE JS::shadow::Zone* shadowZoneFromAnyThread() const {
return JS::shadow::Zone::asShadowZone(zoneFromAnyThread());
}
static MOZ_ALWAYS_INLINE void readBarrier(TenuredCell* thing);
static MOZ_ALWAYS_INLINE void writeBarrierPre(TenuredCell* thing);
static void MOZ_ALWAYS_INLINE writeBarrierPost(void* cellp, TenuredCell* prior,
TenuredCell* next);
// Default implementation for kinds that don't require fixup.
void fixupAfterMovingGC() {}
#ifdef DEBUG
inline bool isAligned() const;
#endif
};
MOZ_ALWAYS_INLINE const TenuredCell&
Cell::asTenured() const
{
MOZ_ASSERT(isTenured());
return *static_cast<const TenuredCell*>(this);
}
MOZ_ALWAYS_INLINE TenuredCell&
Cell::asTenured()
{
MOZ_ASSERT(isTenured());
return *static_cast<TenuredCell*>(this);
}
MOZ_ALWAYS_INLINE bool
Cell::isMarkedAny() const
{
return !isTenured() || asTenured().isMarkedAny();
}
MOZ_ALWAYS_INLINE bool
Cell::isMarkedBlack() const
{
return !isTenured() || asTenured().isMarkedBlack();
}
MOZ_ALWAYS_INLINE bool
Cell::isMarkedGray() const
{
return isTenured() && asTenured().isMarkedGray();
}
inline JSRuntime*
Cell::runtimeFromActiveCooperatingThread() const
{
JSRuntime* rt = chunk()->trailer.runtime;
MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
return rt;
}
inline JSRuntime*
Cell::runtimeFromAnyThread() const
{
return chunk()->trailer.runtime;
}
inline uintptr_t
Cell::address() const
{
uintptr_t addr = uintptr_t(this);
MOZ_ASSERT(addr % CellAlignBytes == 0);
MOZ_ASSERT(Chunk::withinValidRange(addr));
return addr;
}
Chunk*
Cell::chunk() const
{
uintptr_t addr = uintptr_t(this);
MOZ_ASSERT(addr % CellAlignBytes == 0);
addr &= ~ChunkMask;
return reinterpret_cast<Chunk*>(addr);
}
inline StoreBuffer*
Cell::storeBuffer() const
{
return chunk()->trailer.storeBuffer;
}
inline JS::TraceKind
Cell::getTraceKind() const
{
return isTenured() ? asTenured().getTraceKind() : JS::TraceKind::Object;
}
/* static */ MOZ_ALWAYS_INLINE bool
Cell::needWriteBarrierPre(JS::Zone* zone) {
return JS::shadow::Zone::asShadowZone(zone)->needsIncrementalBarrier();
}
/* static */ MOZ_ALWAYS_INLINE TenuredCell*
TenuredCell::fromPointer(void* ptr)
{
MOZ_ASSERT(static_cast<TenuredCell*>(ptr)->isTenured());
return static_cast<TenuredCell*>(ptr);
}
/* static */ MOZ_ALWAYS_INLINE const TenuredCell*
TenuredCell::fromPointer(const void* ptr)
{
MOZ_ASSERT(static_cast<const TenuredCell*>(ptr)->isTenured());
return static_cast<const TenuredCell*>(ptr);
}
bool
TenuredCell::isMarkedAny() const
{
MOZ_ASSERT(arena()->allocated());
return chunk()->bitmap.isMarkedAny(this);
}
bool
TenuredCell::isMarkedBlack() const
{
MOZ_ASSERT(arena()->allocated());
return chunk()->bitmap.isMarkedBlack(this);
}
bool
TenuredCell::isMarkedGray() const
{
MOZ_ASSERT(arena()->allocated());
return chunk()->bitmap.isMarkedGray(this);
}
bool
TenuredCell::markIfUnmarked(MarkColor color /* = Black */) const
{
return chunk()->bitmap.markIfUnmarked(this, color);
}
void
TenuredCell::markBlack() const
{
chunk()->bitmap.markBlack(this);
}
void
TenuredCell::copyMarkBitsFrom(const TenuredCell* src)
{
ChunkBitmap& bitmap = chunk()->bitmap;
bitmap.copyMarkBit(this, src, ColorBit::BlackBit);
bitmap.copyMarkBit(this, src, ColorBit::GrayOrBlackBit);
}
inline Arena*
TenuredCell::arena() const
{
MOZ_ASSERT(isTenured());
uintptr_t addr = address();
addr &= ~ArenaMask;
return reinterpret_cast<Arena*>(addr);
}
AllocKind
TenuredCell::getAllocKind() const
{
return arena()->getAllocKind();
}
JS::TraceKind
TenuredCell::getTraceKind() const
{
return MapAllocToTraceKind(getAllocKind());
}
JS::Zone*
TenuredCell::zone() const
{
JS::Zone* zone = arena()->zone;
MOZ_ASSERT(CurrentThreadCanAccessZone(zone));
return zone;
}
JS::Zone*
TenuredCell::zoneFromAnyThread() const
{
return arena()->zone;
}
bool
TenuredCell::isInsideZone(JS::Zone* zone) const
{
return zone == arena()->zone;
}
/* static */ MOZ_ALWAYS_INLINE void
TenuredCell::readBarrier(TenuredCell* thing)
{
MOZ_ASSERT(!CurrentThreadIsIonCompiling());
MOZ_ASSERT(thing);
MOZ_ASSERT(CurrentThreadCanAccessZone(thing->zoneFromAnyThread()));
// It would be good if barriers were never triggered during collection, but
// at the moment this can happen e.g. when rekeying tables containing
// read-barriered GC things after a moving GC.
//
// TODO: Fix this and assert we're not collecting if we're on the active
// thread.
JS::shadow::Zone* shadowZone = thing->shadowZoneFromAnyThread();
if (shadowZone->needsIncrementalBarrier()) {
// Barriers are only enabled on the active thread and are disabled while collecting.
MOZ_ASSERT(!RuntimeFromActiveCooperatingThreadIsHeapMajorCollecting(shadowZone));
Cell* tmp = thing;
TraceManuallyBarrieredGenericPointerEdge(shadowZone->barrierTracer(), &tmp, "read barrier");
MOZ_ASSERT(tmp == thing);
}
if (thing->isMarkedGray()) {
// There shouldn't be anything marked grey unless we're on the active thread.
MOZ_ASSERT(CurrentThreadCanAccessRuntime(thing->runtimeFromAnyThread()));
if (!RuntimeFromActiveCooperatingThreadIsHeapMajorCollecting(shadowZone))
JS::UnmarkGrayGCThingRecursively(JS::GCCellPtr(thing, thing->getTraceKind()));
}
}
void
AssertSafeToSkipBarrier(TenuredCell* thing);
/* static */ MOZ_ALWAYS_INLINE void
TenuredCell::writeBarrierPre(TenuredCell* thing)
{
MOZ_ASSERT(!CurrentThreadIsIonCompiling());
if (!thing)
return;
#ifdef JS_GC_ZEAL
// When verifying pre barriers we need to switch on all barriers, even
// those on the Atoms Zone. Normally, we never enter a parse task when
// collecting in the atoms zone, so will filter out atoms below.
// Unfortuantely, If we try that when verifying pre-barriers, we'd never be
// able to handle off thread parse tasks at all as we switch on the verifier any
// time we're not doing GC. This would cause us to deadlock, as off thread parsing
// is meant to resume after GC work completes. Instead we filter out any
// off thread barriers that reach us and assert that they would normally not be
// possible.
if (!CurrentThreadCanAccessRuntime(thing->runtimeFromAnyThread())) {
AssertSafeToSkipBarrier(thing);
return;
}
#endif
JS::shadow::Zone* shadowZone = thing->shadowZoneFromAnyThread();
if (shadowZone->needsIncrementalBarrier()) {
MOZ_ASSERT(!RuntimeFromActiveCooperatingThreadIsHeapMajorCollecting(shadowZone));
Cell* tmp = thing;
TraceManuallyBarrieredGenericPointerEdge(shadowZone->barrierTracer(), &tmp, "pre barrier");
MOZ_ASSERT(tmp == thing);
}
}
static MOZ_ALWAYS_INLINE void
AssertValidToSkipBarrier(TenuredCell* thing)
{
MOZ_ASSERT(!IsInsideNursery(thing));
MOZ_ASSERT_IF(thing, MapAllocToTraceKind(thing->getAllocKind()) != JS::TraceKind::Object);
}
/* static */ MOZ_ALWAYS_INLINE void
TenuredCell::writeBarrierPost(void* cellp, TenuredCell* prior, TenuredCell* next)
{
AssertValidToSkipBarrier(next);
}
#ifdef DEBUG
bool
Cell::isAligned() const
{
if (!isTenured())
return true;
return asTenured().isAligned();
}
bool
TenuredCell::isAligned() const
{
return Arena::isAligned(address(), arena()->getThingSize());
}
#endif
} /* namespace gc */
} /* namespace js */
#endif /* gc_Cell_h */

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше