mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-01 17:23:59 +00:00
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
commit
bb87f43c09
@ -338,6 +338,21 @@ DocAccessibleParent::RecvTextChangeEvent(const uint64_t& aID,
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
#if defined(XP_WIN)
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
DocAccessibleParent::RecvSyncTextChangeEvent(const uint64_t& aID,
|
||||
const nsString& aStr,
|
||||
const int32_t& aStart,
|
||||
const uint32_t& aLen,
|
||||
const bool& aIsInsert,
|
||||
const bool& aFromUser)
|
||||
{
|
||||
return RecvTextChangeEvent(aID, aStr, aStart, aLen, aIsInsert, aFromUser);
|
||||
}
|
||||
|
||||
#endif // defined(XP_WIN)
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
DocAccessibleParent::RecvSelectionEvent(const uint64_t& aID,
|
||||
const uint64_t& aWidgetID,
|
||||
@ -436,6 +451,11 @@ DocAccessibleParent::AddChildDoc(DocAccessibleParent* aChildDoc,
|
||||
return IPC_FAIL(this, "binding to proxy that can't be a outerDoc!");
|
||||
}
|
||||
|
||||
if (outerDoc->ChildrenCount() == 1) {
|
||||
MOZ_ASSERT(outerDoc->ChildAt(0)->AsDoc());
|
||||
outerDoc->ChildAt(0)->AsDoc()->Unbind();
|
||||
}
|
||||
|
||||
aChildDoc->SetParent(outerDoc);
|
||||
outerDoc->SetChildDoc(aChildDoc);
|
||||
mChildDocs.AppendElement(aChildDoc->mActorID);
|
||||
|
@ -88,6 +88,13 @@ public:
|
||||
const bool& aIsInsert,
|
||||
const bool& aFromUser) override;
|
||||
|
||||
#if defined(XP_WIN)
|
||||
virtual mozilla::ipc::IPCResult RecvSyncTextChangeEvent(const uint64_t& aID, const nsString& aStr,
|
||||
const int32_t& aStart, const uint32_t& aLen,
|
||||
const bool& aIsInsert,
|
||||
const bool& aFromUser) override;
|
||||
#endif // defined(XP_WIN)
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvSelectionEvent(const uint64_t& aID,
|
||||
const uint64_t& aWidgetID,
|
||||
const uint32_t& aType) override;
|
||||
|
@ -54,15 +54,9 @@ template <class Derived>
|
||||
void
|
||||
ProxyAccessibleBase<Derived>::SetChildDoc(DocAccessibleParent* aChildDoc)
|
||||
{
|
||||
// DocAccessibleParent::AddChildDoc tolerates replacing one document with
|
||||
// another. We must reflect that here.
|
||||
MOZ_ASSERT(aChildDoc);
|
||||
MOZ_ASSERT(mChildren.Length() <= 1);
|
||||
if (mChildren.IsEmpty()) {
|
||||
mChildren.AppendElement(aChildDoc);
|
||||
} else {
|
||||
mChildren.ReplaceElementAt(0, aChildDoc);
|
||||
}
|
||||
MOZ_ASSERT(mChildren.Length() == 0);
|
||||
mChildren.AppendElement(aChildDoc);
|
||||
mOuterDoc = true;
|
||||
}
|
||||
|
||||
|
@ -77,6 +77,18 @@ DocAccessibleChild::RecvEmulatedWindow(const WindowsHandle& aEmulatedWindowHandl
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
HWND
|
||||
DocAccessibleChild::GetNativeWindowHandle() const
|
||||
{
|
||||
if (mEmulatedWindowHandle) {
|
||||
return mEmulatedWindowHandle;
|
||||
}
|
||||
|
||||
auto tab = static_cast<dom::TabChild*>(Manager());
|
||||
MOZ_ASSERT(tab);
|
||||
return reinterpret_cast<HWND>(tab->GetNativeWindowHandle());
|
||||
}
|
||||
|
||||
void
|
||||
DocAccessibleChild::PushDeferredEvent(UniquePtr<DeferredEvent> aEvent)
|
||||
{
|
||||
@ -178,6 +190,13 @@ DocAccessibleChild::SendTextChangeEvent(const uint64_t& aID,
|
||||
const bool& aFromUser)
|
||||
{
|
||||
if (IsConstructedInParentProcess()) {
|
||||
if (aStr.Contains(L'\xfffc')) {
|
||||
// The AT is going to need to reenter content while the event is being
|
||||
// dispatched synchronously.
|
||||
return PDocAccessibleChild::SendSyncTextChangeEvent(aID, aStr, aStart,
|
||||
aLen, aIsInsert,
|
||||
aFromUser);
|
||||
}
|
||||
return PDocAccessibleChild::SendTextChangeEvent(aID, aStr, aStart,
|
||||
aLen, aIsInsert, aFromUser);
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ public:
|
||||
RecvEmulatedWindow(const WindowsHandle& aEmulatedWindowHandle,
|
||||
const IAccessibleHolder& aEmulatedWindowCOMProxy) override;
|
||||
|
||||
HWND GetEmulatedWindowHandle() const { return mEmulatedWindowHandle; }
|
||||
HWND GetNativeWindowHandle() const;
|
||||
IAccessible* GetEmulatedWindowIAccessible() const { return mEmulatedWindowProxy.get(); }
|
||||
|
||||
IAccessible* GetParentIAccessible() const { return mParentProxy.get(); }
|
||||
|
@ -53,6 +53,8 @@ parent:
|
||||
async CaretMoveEvent(uint64_t aID, int32_t aOffset);
|
||||
async TextChangeEvent(uint64_t aID, nsString aStr, int32_t aStart, uint32_t aLen,
|
||||
bool aIsInsert, bool aFromUser);
|
||||
sync SyncTextChangeEvent(uint64_t aID, nsString aStr, int32_t aStart,
|
||||
uint32_t aLen, bool aIsInsert, bool aFromUser);
|
||||
async SelectionEvent(uint64_t aID, uint64_t aWidgetID, uint32_t aType);
|
||||
async RoleChangedEvent(uint32_t aRole);
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "AccessibleHandler.h"
|
||||
#include "AccessibleHandlerControl.h"
|
||||
#include "AccessibleTextTearoff.h"
|
||||
|
||||
#include "Factory.h"
|
||||
#include "HandlerData.h"
|
||||
@ -183,6 +184,12 @@ AccessibleHandler::QueryHandlerInterface(IUnknown* aProxyUnknown, REFIID aIid,
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (aIid == IID_IAccessibleText || aIid == IID_IAccessibleHypertext) {
|
||||
RefPtr<IAccessibleHypertext> textTearoff(new AccessibleTextTearoff(this));
|
||||
textTearoff.forget(aOutInterface);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (aIid == IID_IProvideClassInfo) {
|
||||
RefPtr<IProvideClassInfo> clsInfo(this);
|
||||
clsInfo.forget(aOutInterface);
|
||||
|
@ -22,6 +22,103 @@ namespace a11y {
|
||||
|
||||
mscom::SingletonFactory<AccessibleHandlerControl> gControlFactory;
|
||||
|
||||
namespace detail {
|
||||
|
||||
TextChange::TextChange()
|
||||
: mIA2UniqueId(0)
|
||||
, mIsInsert(false)
|
||||
, mText()
|
||||
{
|
||||
}
|
||||
|
||||
TextChange::TextChange(long aIA2UniqueId, bool aIsInsert,
|
||||
NotNull<IA2TextSegment*> aText)
|
||||
: mIA2UniqueId(aIA2UniqueId)
|
||||
, mIsInsert(aIsInsert)
|
||||
, mText{BSTRCopy(aText->text), aText->start, aText->end}
|
||||
{
|
||||
}
|
||||
|
||||
TextChange::TextChange(TextChange&& aOther)
|
||||
: mText()
|
||||
{
|
||||
*this = Move(aOther);
|
||||
}
|
||||
|
||||
TextChange::TextChange(const TextChange& aOther)
|
||||
: mText()
|
||||
{
|
||||
*this = aOther;
|
||||
}
|
||||
|
||||
TextChange&
|
||||
TextChange::operator=(TextChange&& aOther)
|
||||
{
|
||||
mIA2UniqueId = aOther.mIA2UniqueId;
|
||||
mIsInsert = aOther.mIsInsert;
|
||||
aOther.mIA2UniqueId = 0;
|
||||
::SysFreeString(mText.text);
|
||||
mText = aOther.mText;
|
||||
aOther.mText.text = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TextChange&
|
||||
TextChange::operator=(const TextChange& aOther)
|
||||
{
|
||||
mIA2UniqueId = aOther.mIA2UniqueId;
|
||||
mIsInsert = aOther.mIsInsert;
|
||||
::SysFreeString(mText.text);
|
||||
mText = {BSTRCopy(aOther.mText.text), aOther.mText.start, aOther.mText.end};
|
||||
return *this;
|
||||
}
|
||||
|
||||
TextChange::~TextChange()
|
||||
{
|
||||
::SysFreeString(mText.text);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
TextChange::GetOld(long aIA2UniqueId, NotNull<IA2TextSegment*> aOutOldSegment)
|
||||
{
|
||||
if (mIsInsert || aIA2UniqueId != mIA2UniqueId) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return SegCopy(*aOutOldSegment, mText);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
TextChange::GetNew(long aIA2UniqueId, NotNull<IA2TextSegment*> aOutNewSegment)
|
||||
{
|
||||
if (!mIsInsert || aIA2UniqueId != mIA2UniqueId) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return SegCopy(*aOutNewSegment, mText);
|
||||
}
|
||||
|
||||
/* static */ BSTR
|
||||
TextChange::BSTRCopy(const BSTR& aIn)
|
||||
{
|
||||
return ::SysAllocStringLen(aIn, ::SysStringLen(aIn));
|
||||
}
|
||||
|
||||
/* static */ HRESULT
|
||||
TextChange::SegCopy(IA2TextSegment& aDest, const IA2TextSegment& aSrc)
|
||||
{
|
||||
aDest = {BSTRCopy(aSrc.text), aSrc.start, aSrc.end};
|
||||
if (aSrc.text && !aDest.text) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
if (!::SysStringLen(aDest.text)) {
|
||||
return S_FALSE;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
HRESULT
|
||||
AccessibleHandlerControl::Create(AccessibleHandlerControl** aOutObject)
|
||||
{
|
||||
@ -35,46 +132,14 @@ AccessibleHandlerControl::Create(AccessibleHandlerControl** aOutObject)
|
||||
}
|
||||
|
||||
AccessibleHandlerControl::AccessibleHandlerControl()
|
||||
: mRefCnt(0)
|
||||
, mCacheGen(0)
|
||||
: mCacheGen(0)
|
||||
, mIA2Proxy(mscom::RegisterProxy(L"ia2marshal.dll"))
|
||||
, mHandlerProxy(mscom::RegisterProxy())
|
||||
{
|
||||
MOZ_ASSERT(mIA2Proxy);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleHandlerControl::QueryInterface(REFIID aIid, void** aOutInterface)
|
||||
{
|
||||
if (!aOutInterface) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (aIid == IID_IUnknown || aIid == IID_IHandlerControl) {
|
||||
RefPtr<IHandlerControl> ctl(this);
|
||||
ctl.forget(aOutInterface);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
*aOutInterface = nullptr;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
ULONG
|
||||
AccessibleHandlerControl::AddRef()
|
||||
{
|
||||
return ++mRefCnt;
|
||||
}
|
||||
|
||||
ULONG
|
||||
AccessibleHandlerControl::Release()
|
||||
{
|
||||
ULONG result = --mRefCnt;
|
||||
if (!result) {
|
||||
delete this;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
IMPL_IUNKNOWN1(AccessibleHandlerControl, IHandlerControl)
|
||||
|
||||
HRESULT
|
||||
AccessibleHandlerControl::Invalidate()
|
||||
@ -83,6 +148,36 @@ AccessibleHandlerControl::Invalidate()
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleHandlerControl::OnTextChange(long aHwnd, long aIA2UniqueId,
|
||||
VARIANT_BOOL aIsInsert,
|
||||
IA2TextSegment* aText)
|
||||
{
|
||||
if (!aText) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
mTextChange = detail::TextChange(aIA2UniqueId, aIsInsert, WrapNotNull(aText));
|
||||
NotifyWinEvent(aIsInsert ? IA2_EVENT_TEXT_INSERTED : IA2_EVENT_TEXT_REMOVED,
|
||||
reinterpret_cast<HWND>(static_cast<uintptr_t>(aHwnd)),
|
||||
OBJID_CLIENT, aIA2UniqueId);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleHandlerControl::GetNewText(long aIA2UniqueId,
|
||||
NotNull<IA2TextSegment*> aOutNewText)
|
||||
{
|
||||
return mTextChange.GetNew(aIA2UniqueId, aOutNewText);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleHandlerControl::GetOldText(long aIA2UniqueId,
|
||||
NotNull<IA2TextSegment*> aOutOldText)
|
||||
{
|
||||
return mTextChange.GetOld(aIA2UniqueId, aOutOldText);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleHandlerControl::GetHandlerTypeInfo(ITypeInfo** aOutTypeInfo)
|
||||
{
|
||||
|
@ -13,37 +13,70 @@
|
||||
|
||||
#include "Factory.h"
|
||||
#include "HandlerData.h"
|
||||
#include "IUnknownImpl.h"
|
||||
#include "mozilla/mscom/Registration.h"
|
||||
#include "mozilla/NotNull.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
namespace detail {
|
||||
|
||||
class TextChange final
|
||||
{
|
||||
public:
|
||||
TextChange();
|
||||
TextChange(long aIA2UniqueId, bool aIsInsert, NotNull<IA2TextSegment*> aText);
|
||||
TextChange(TextChange&& aOther);
|
||||
TextChange(const TextChange& aOther);
|
||||
|
||||
TextChange& operator=(TextChange&& aOther);
|
||||
TextChange& operator=(const TextChange& aOther);
|
||||
|
||||
~TextChange();
|
||||
|
||||
HRESULT GetOld(long aIA2UniqueId, NotNull<IA2TextSegment*> aOutOldSegment);
|
||||
HRESULT GetNew(long aIA2UniqueId, NotNull<IA2TextSegment*> aOutNewSegment);
|
||||
|
||||
private:
|
||||
static BSTR BSTRCopy(const BSTR& aIn);
|
||||
static HRESULT SegCopy(IA2TextSegment& aDest, const IA2TextSegment& aSrc);
|
||||
|
||||
long mIA2UniqueId;
|
||||
bool mIsInsert;
|
||||
IA2TextSegment mText;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
class AccessibleHandlerControl final : public IHandlerControl
|
||||
{
|
||||
public:
|
||||
static HRESULT Create(AccessibleHandlerControl** aOutObject);
|
||||
|
||||
// IUnknown
|
||||
STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
|
||||
STDMETHODIMP_(ULONG) AddRef() override;
|
||||
STDMETHODIMP_(ULONG) Release() override;
|
||||
DECL_IUNKNOWN
|
||||
|
||||
// IHandlerControl
|
||||
STDMETHODIMP Invalidate() override;
|
||||
STDMETHODIMP OnTextChange(long aHwnd, long aIA2UniqueId,
|
||||
VARIANT_BOOL aIsInsert, IA2TextSegment* aText) override;
|
||||
|
||||
uint32_t GetCacheGen() const
|
||||
{
|
||||
return mCacheGen;
|
||||
}
|
||||
|
||||
HRESULT GetNewText(long aIA2UniqueId, NotNull<IA2TextSegment*> aOutNewText);
|
||||
HRESULT GetOldText(long aIA2UniqueId, NotNull<IA2TextSegment*> aOutOldText);
|
||||
|
||||
HRESULT GetHandlerTypeInfo(ITypeInfo** aOutTypeInfo);
|
||||
|
||||
private:
|
||||
AccessibleHandlerControl();
|
||||
~AccessibleHandlerControl() = default;
|
||||
|
||||
ULONG mRefCnt;
|
||||
uint32_t mCacheGen;
|
||||
detail::TextChange mTextChange;
|
||||
UniquePtr<mscom::RegisteredProxy> mIA2Proxy;
|
||||
UniquePtr<mscom::RegisteredProxy> mHandlerProxy;
|
||||
};
|
||||
|
359
accessible/ipc/win/handler/AccessibleTextTearoff.cpp
Normal file
359
accessible/ipc/win/handler/AccessibleTextTearoff.cpp
Normal file
@ -0,0 +1,359 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
#error This code is NOT for internal Gecko use!
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
#include "AccessibleTextTearoff.h"
|
||||
|
||||
#include "AccessibleHandlerControl.h"
|
||||
#include "AccessibleText_i.c"
|
||||
#include "AccessibleHypertext_i.c"
|
||||
#include "Factory.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
AccessibleTextTearoff::AccessibleTextTearoff(AccessibleHandler* aHandler)
|
||||
: mHandler(aHandler)
|
||||
{
|
||||
MOZ_ASSERT(aHandler);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleTextTearoff::ResolveAccText()
|
||||
{
|
||||
if (mAccTextProxy) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
RefPtr<IUnknown> proxy(mHandler->GetProxy());
|
||||
if (!proxy) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
return proxy->QueryInterface(IID_IAccessibleText,
|
||||
getter_AddRefs(mAccTextProxy));
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleTextTearoff::ResolveAccHypertext()
|
||||
{
|
||||
if (mAccHypertextProxy) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
RefPtr<IUnknown> proxy(mHandler->GetProxy());
|
||||
if (!proxy) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
return proxy->QueryInterface(IID_IAccessibleHypertext,
|
||||
getter_AddRefs(mAccHypertextProxy));
|
||||
}
|
||||
|
||||
IMPL_IUNKNOWN_QUERY_HEAD(AccessibleTextTearoff)
|
||||
IMPL_IUNKNOWN_QUERY_IFACE(IAccessibleText)
|
||||
IMPL_IUNKNOWN_QUERY_IFACE(IAccessibleHypertext)
|
||||
IMPL_IUNKNOWN_QUERY_TAIL_AGGREGATED(mHandler)
|
||||
|
||||
HRESULT
|
||||
AccessibleTextTearoff::addSelection(long startOffset, long endOffset)
|
||||
{
|
||||
HRESULT hr = ResolveAccText();
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return mAccTextProxy->addSelection(startOffset, endOffset);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleTextTearoff::get_attributes(long offset, long *startOffset,
|
||||
long *endOffset, BSTR *textAttributes)
|
||||
{
|
||||
HRESULT hr = ResolveAccText();
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return mAccTextProxy->get_attributes(offset, startOffset, endOffset,
|
||||
textAttributes);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleTextTearoff::get_caretOffset(long *offset)
|
||||
{
|
||||
HRESULT hr = ResolveAccText();
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return mAccTextProxy->get_caretOffset(offset);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleTextTearoff::get_characterExtents(long offset,
|
||||
enum IA2CoordinateType coordType,
|
||||
long *x, long *y, long *width,
|
||||
long *height)
|
||||
{
|
||||
HRESULT hr = ResolveAccText();
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return mAccTextProxy->get_characterExtents(offset, coordType, x, y, width,
|
||||
height);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleTextTearoff::get_nSelections(long *nSelections)
|
||||
{
|
||||
HRESULT hr = ResolveAccText();
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return mAccTextProxy->get_nSelections(nSelections);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleTextTearoff::get_offsetAtPoint(long x, long y,
|
||||
enum IA2CoordinateType coordType,
|
||||
long *offset)
|
||||
{
|
||||
HRESULT hr = ResolveAccText();
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return mAccTextProxy->get_offsetAtPoint(x, y, coordType, offset);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleTextTearoff::get_selection(long selectionIndex, long *startOffset,
|
||||
long *endOffset)
|
||||
{
|
||||
HRESULT hr = ResolveAccText();
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return mAccTextProxy->get_selection(selectionIndex, startOffset, endOffset);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleTextTearoff::get_text(long startOffset, long endOffset, BSTR *text)
|
||||
{
|
||||
HRESULT hr = ResolveAccText();
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return mAccTextProxy->get_text(startOffset, endOffset, text);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleTextTearoff::get_textBeforeOffset(long offset,
|
||||
enum IA2TextBoundaryType boundaryType,
|
||||
long *startOffset, long *endOffset,
|
||||
BSTR *text)
|
||||
{
|
||||
HRESULT hr = ResolveAccText();
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return mAccTextProxy->get_textBeforeOffset(offset, boundaryType, startOffset,
|
||||
endOffset, text);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleTextTearoff::get_textAfterOffset(long offset,
|
||||
enum IA2TextBoundaryType boundaryType,
|
||||
long *startOffset, long *endOffset,
|
||||
BSTR *text)
|
||||
{
|
||||
HRESULT hr = ResolveAccText();
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return mAccTextProxy->get_textAfterOffset(offset, boundaryType,
|
||||
startOffset, endOffset, text);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleTextTearoff::get_textAtOffset(long offset,
|
||||
enum IA2TextBoundaryType boundaryType,
|
||||
long *startOffset, long *endOffset,
|
||||
BSTR *text)
|
||||
{
|
||||
HRESULT hr = ResolveAccText();
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return mAccTextProxy->get_textAtOffset(offset, boundaryType, startOffset,
|
||||
endOffset, text);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleTextTearoff::removeSelection(long selectionIndex)
|
||||
{
|
||||
HRESULT hr = ResolveAccText();
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return mAccTextProxy->removeSelection(selectionIndex);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleTextTearoff::setCaretOffset(long offset)
|
||||
{
|
||||
HRESULT hr = ResolveAccText();
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return mAccTextProxy->setCaretOffset(offset);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleTextTearoff::setSelection(long selectionIndex, long startOffset,
|
||||
long endOffset)
|
||||
{
|
||||
HRESULT hr = ResolveAccText();
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return mAccTextProxy->setSelection(selectionIndex, startOffset, endOffset);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleTextTearoff::get_nCharacters(long *nCharacters)
|
||||
{
|
||||
HRESULT hr = ResolveAccText();
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return mAccTextProxy->get_nCharacters(nCharacters);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleTextTearoff::scrollSubstringTo(long startIndex, long endIndex,
|
||||
enum IA2ScrollType scrollType)
|
||||
{
|
||||
HRESULT hr = ResolveAccText();
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return mAccTextProxy->scrollSubstringTo(startIndex, endIndex, scrollType);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleTextTearoff::scrollSubstringToPoint(long startIndex, long endIndex,
|
||||
enum IA2CoordinateType coordinateType,
|
||||
long x, long y)
|
||||
{
|
||||
HRESULT hr = ResolveAccText();
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return mAccTextProxy->scrollSubstringToPoint(startIndex, endIndex,
|
||||
coordinateType, x, y);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleTextTearoff::get_newText(IA2TextSegment *newText)
|
||||
{
|
||||
if (!newText) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
RefPtr<AccessibleHandlerControl> ctl(gControlFactory.GetSingleton());
|
||||
MOZ_ASSERT(ctl);
|
||||
if (!ctl) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
long id;
|
||||
HRESULT hr = mHandler->get_uniqueID(&id);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return ctl->GetNewText(id, WrapNotNull(newText));
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleTextTearoff::get_oldText(IA2TextSegment *oldText)
|
||||
{
|
||||
if (!oldText) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
RefPtr<AccessibleHandlerControl> ctl(gControlFactory.GetSingleton());
|
||||
MOZ_ASSERT(ctl);
|
||||
if (!ctl) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
long id;
|
||||
HRESULT hr = mHandler->get_uniqueID(&id);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return ctl->GetOldText(id, WrapNotNull(oldText));
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleTextTearoff::get_nHyperlinks(long *hyperlinkCount)
|
||||
{
|
||||
HRESULT hr = ResolveAccHypertext();
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return mAccHypertextProxy->get_nHyperlinks(hyperlinkCount);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleTextTearoff::get_hyperlink(long index,
|
||||
IAccessibleHyperlink **hyperlink)
|
||||
{
|
||||
HRESULT hr = ResolveAccHypertext();
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return mAccHypertextProxy->get_hyperlink(index, hyperlink);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleTextTearoff::get_hyperlinkIndex(long charIndex, long *hyperlinkIndex)
|
||||
{
|
||||
HRESULT hr = ResolveAccHypertext();
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return mAccHypertextProxy->get_hyperlinkIndex(charIndex, hyperlinkIndex);
|
||||
}
|
||||
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
88
accessible/ipc/win/handler/AccessibleTextTearoff.h
Normal file
88
accessible/ipc/win/handler/AccessibleTextTearoff.h
Normal file
@ -0,0 +1,88 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
#error This code is NOT for internal Gecko use!
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
|
||||
#ifndef mozilla_a11y_AccessibleTextTearoff_h
|
||||
#define mozilla_a11y_AccessibleTextTearoff_h
|
||||
|
||||
#include "AccessibleHandler.h"
|
||||
#include "AccessibleHypertext.h"
|
||||
#include "IUnknownImpl.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
class AccessibleTextTearoff final : public IAccessibleHypertext
|
||||
{
|
||||
public:
|
||||
explicit AccessibleTextTearoff(AccessibleHandler* aHandler);
|
||||
|
||||
DECL_IUNKNOWN
|
||||
|
||||
// IAccessibleText
|
||||
STDMETHODIMP addSelection(long startOffset, long endOffset) override;
|
||||
STDMETHODIMP get_attributes(long offset, long *startOffset, long *endOffset,
|
||||
BSTR *textAttributes) override;
|
||||
STDMETHODIMP get_caretOffset(long *offset) override;
|
||||
STDMETHODIMP get_characterExtents(long offset,
|
||||
enum IA2CoordinateType coordType, long *x,
|
||||
long *y, long *width, long *height) override;
|
||||
STDMETHODIMP get_nSelections(long *nSelections) override;
|
||||
STDMETHODIMP get_offsetAtPoint(long x, long y,
|
||||
enum IA2CoordinateType coordType,
|
||||
long *offset) override;
|
||||
STDMETHODIMP get_selection(long selectionIndex, long *startOffset,
|
||||
long *endOffset) override;
|
||||
STDMETHODIMP get_text(long startOffset, long endOffset, BSTR *text) override;
|
||||
STDMETHODIMP get_textBeforeOffset(long offset,
|
||||
enum IA2TextBoundaryType boundaryType,
|
||||
long *startOffset, long *endOffset,
|
||||
BSTR *text) override;
|
||||
STDMETHODIMP get_textAfterOffset(long offset,
|
||||
enum IA2TextBoundaryType boundaryType,
|
||||
long *startOffset, long *endOffset,
|
||||
BSTR *text) override;
|
||||
STDMETHODIMP get_textAtOffset(long offset,
|
||||
enum IA2TextBoundaryType boundaryType,
|
||||
long *startOffset, long *endOffset,
|
||||
BSTR *text) override;
|
||||
STDMETHODIMP removeSelection(long selectionIndex) override;
|
||||
STDMETHODIMP setCaretOffset(long offset) override;
|
||||
STDMETHODIMP setSelection(long selectionIndex, long startOffset,
|
||||
long endOffset) override;
|
||||
STDMETHODIMP get_nCharacters(long *nCharacters) override;
|
||||
STDMETHODIMP scrollSubstringTo(long startIndex, long endIndex,
|
||||
enum IA2ScrollType scrollType) override;
|
||||
STDMETHODIMP scrollSubstringToPoint(long startIndex, long endIndex,
|
||||
enum IA2CoordinateType coordinateType,
|
||||
long x, long y) override;
|
||||
STDMETHODIMP get_newText(IA2TextSegment *newText) override;
|
||||
STDMETHODIMP get_oldText(IA2TextSegment *oldText) override;
|
||||
|
||||
// IAccessibleHypertext
|
||||
STDMETHODIMP get_nHyperlinks(long *hyperlinkCount) override;
|
||||
STDMETHODIMP get_hyperlink(long index,
|
||||
IAccessibleHyperlink **hyperlink) override;
|
||||
STDMETHODIMP get_hyperlinkIndex(long charIndex, long *hyperlinkIndex) override;
|
||||
|
||||
private:
|
||||
~AccessibleTextTearoff() = default;
|
||||
HRESULT ResolveAccText();
|
||||
HRESULT ResolveAccHypertext();
|
||||
|
||||
RefPtr<AccessibleHandler> mHandler;
|
||||
RefPtr<IAccessibleText> mAccTextProxy;
|
||||
RefPtr<IAccessibleHypertext> mAccHypertextProxy;
|
||||
};
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_a11y_AccessibleTextTearoff_h
|
@ -9,6 +9,8 @@
|
||||
import "ocidl.idl";
|
||||
import "ServProv.idl";
|
||||
|
||||
import "AccessibleText.idl";
|
||||
|
||||
typedef struct _IA2Data
|
||||
{
|
||||
long mUniqueId;
|
||||
@ -84,6 +86,9 @@ interface HandlerData
|
||||
interface IHandlerControl : IUnknown
|
||||
{
|
||||
HRESULT Invalidate();
|
||||
HRESULT OnTextChange([in] long aHwnd, [in] long aIA2UniqueId,
|
||||
[in] VARIANT_BOOL aIsInsert,
|
||||
[in] IA2TextSegment* aText);
|
||||
}
|
||||
|
||||
[object,
|
||||
|
@ -20,6 +20,7 @@ SOURCES += [
|
||||
'!HandlerData_p.c',
|
||||
'AccessibleHandler.cpp',
|
||||
'AccessibleHandlerControl.cpp',
|
||||
'AccessibleTextTearoff.cpp',
|
||||
]
|
||||
|
||||
GENERATED_FILES += [
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "nsArrayUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsIXULRuntime.h"
|
||||
#include "mozilla/mscom/AsyncInvoker.h"
|
||||
|
||||
#include "oleacc.h"
|
||||
|
||||
@ -1627,3 +1628,60 @@ AccessibleWrap::SetHandlerControl(DWORD aPid, RefPtr<IHandlerControl> aCtrl)
|
||||
sHandlerControllers->AppendElement(Move(ctrlData));
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
AccessibleWrap::DispatchTextChangeToHandler(bool aIsInsert,
|
||||
const nsString& aText,
|
||||
int32_t aStart, uint32_t aLen)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!sHandlerControllers || sHandlerControllers->IsEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HWND hwnd = GetHWNDFor(this);
|
||||
MOZ_ASSERT(hwnd);
|
||||
if (!hwnd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
long msaaId = GetChildIDFor(this);
|
||||
|
||||
DWORD ourPid = ::GetCurrentProcessId();
|
||||
|
||||
// The handler ends up calling NotifyWinEvent, which should only be done once
|
||||
// since it broadcasts the same event to every process who is subscribed.
|
||||
// OTOH, if our chrome process contains a handler, we should prefer to
|
||||
// broadcast the event from that process, as we want any DLLs injected by ATs
|
||||
// to receive the event synchronously. Otherwise we simply choose the first
|
||||
// handler in the list, for the lack of a better heuristic.
|
||||
|
||||
nsTArray<HandlerControllerData>::index_type ctrlIndex =
|
||||
sHandlerControllers->IndexOf(ourPid);
|
||||
|
||||
if (ctrlIndex == nsTArray<HandlerControllerData>::NoIndex) {
|
||||
ctrlIndex = 0;
|
||||
}
|
||||
|
||||
HandlerControllerData& controller = sHandlerControllers->ElementAt(ctrlIndex);
|
||||
MOZ_ASSERT(controller.mPid);
|
||||
MOZ_ASSERT(controller.mCtrl);
|
||||
|
||||
VARIANT_BOOL isInsert = aIsInsert ? VARIANT_TRUE : VARIANT_FALSE;
|
||||
|
||||
IA2TextSegment textSegment{::SysAllocStringLen(aText.get(), aText.Length()),
|
||||
aStart, static_cast<long>(aLen)};
|
||||
|
||||
ASYNC_INVOKER_FOR(IHandlerControl) invoker(controller.mCtrl,
|
||||
Some(controller.mIsProxy));
|
||||
|
||||
HRESULT hr = ASYNC_INVOKE(invoker, OnTextChange, PtrToLong(hwnd), msaaId,
|
||||
isInsert, &textSegment);
|
||||
|
||||
::SysFreeString(textSegment.text);
|
||||
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
|
@ -192,6 +192,8 @@ public: // construction, destruction
|
||||
|
||||
static void SetHandlerControl(DWORD aPid, RefPtr<IHandlerControl> aCtrl);
|
||||
|
||||
bool DispatchTextChangeToHandler(bool aIsInsert, const nsString& aText,
|
||||
int32_t aStart, uint32_t aLen);
|
||||
protected:
|
||||
virtual ~AccessibleWrap();
|
||||
|
||||
|
@ -131,18 +131,7 @@ DocAccessibleWrap::GetNativeWindow() const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HWND hWnd = ipcDoc->GetEmulatedWindowHandle();
|
||||
if (hWnd) {
|
||||
return hWnd;
|
||||
}
|
||||
|
||||
auto tab = static_cast<dom::TabChild*>(ipcDoc->Manager());
|
||||
MOZ_ASSERT(tab);
|
||||
if (!tab) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return reinterpret_cast<HWND>(tab->GetNativeWindowHandle());
|
||||
return ipcDoc->GetNativeWindowHandle();
|
||||
} else if (mHWND) {
|
||||
return mHWND;
|
||||
}
|
||||
|
@ -132,6 +132,14 @@ a11y::ProxyTextChangeEvent(ProxyAccessible* aText, const nsString& aStr,
|
||||
return;
|
||||
}
|
||||
|
||||
static const bool useHandler =
|
||||
Preferences::GetBool("accessibility.handler.enabled", false);
|
||||
|
||||
if (useHandler) {
|
||||
wrapper->DispatchTextChangeToHandler(aInsert, aStr, aStart, aLen);
|
||||
return;
|
||||
}
|
||||
|
||||
auto text = static_cast<HyperTextAccessibleWrap*>(wrapper->AsHyperText());
|
||||
if (text) {
|
||||
ia2AccessibleText::UpdateTextChangeData(text, aInsert, aStr, aStart, aLen);
|
||||
|
@ -62,6 +62,37 @@ this.sessions = class extends ExtensionAPI {
|
||||
return Promise.resolve(getRecentlyClosed(maxResults, extension));
|
||||
},
|
||||
|
||||
forgetClosedTab: function(windowId, sessionId) {
|
||||
let window = context.extension.windowManager.get(windowId).window;
|
||||
let closedTabData = SessionStore.getClosedTabData(window, false);
|
||||
|
||||
let closedTabIndex = closedTabData.findIndex((closedTab) => {
|
||||
return closedTab.closedId === parseInt(sessionId, 10);
|
||||
});
|
||||
|
||||
if (closedTabIndex < 0) {
|
||||
return Promise.reject({message: `Could not find closed tab using sessionId ${sessionId}.`});
|
||||
}
|
||||
|
||||
SessionStore.forgetClosedTab(window, closedTabIndex);
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
forgetClosedWindow: function(sessionId) {
|
||||
let closedWindowData = SessionStore.getClosedWindowData(false);
|
||||
|
||||
let closedWindowIndex = closedWindowData.findIndex((closedWindow) => {
|
||||
return closedWindow.closedId === parseInt(sessionId, 10);
|
||||
});
|
||||
|
||||
if (closedWindowIndex < 0) {
|
||||
return Promise.reject({message: `Could not find closed window using sessionId ${sessionId}.`});
|
||||
}
|
||||
|
||||
SessionStore.forgetClosedWindow(closedWindowIndex);
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
restore: function(sessionId) {
|
||||
let session, closedId;
|
||||
if (sessionId) {
|
||||
|
@ -55,6 +55,37 @@
|
||||
}
|
||||
],
|
||||
"functions": [
|
||||
{
|
||||
"name": "forgetClosedTab",
|
||||
"type": "function",
|
||||
"description": "Forget a recently closed tab.",
|
||||
"async": true,
|
||||
"parameters": [
|
||||
{
|
||||
"name": "windowId",
|
||||
"type": "integer",
|
||||
"description": "The windowId of the window to which the recently closed tab to be forgotten belongs."
|
||||
},
|
||||
{
|
||||
"name": "sessionId",
|
||||
"type": "string",
|
||||
"description": "The sessionId (closedId) of the recently closed tab to be forgotten."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "forgetClosedWindow",
|
||||
"type": "function",
|
||||
"description": "Forget a recently closed window.",
|
||||
"async": true,
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionId",
|
||||
"type": "string",
|
||||
"description": "The sessionId (closedId) of the recently closed window to be forgotten."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "getRecentlyClosed",
|
||||
"type": "function",
|
||||
|
@ -82,6 +82,8 @@ support-files =
|
||||
[browser_ext_runtime_openOptionsPage.js]
|
||||
[browser_ext_runtime_openOptionsPage_uninstall.js]
|
||||
[browser_ext_runtime_setUninstallURL.js]
|
||||
[browser_ext_sessions_forgetClosedTab.js]
|
||||
[browser_ext_sessions_forgetClosedWindow.js]
|
||||
[browser_ext_sessions_getRecentlyClosed.js]
|
||||
[browser_ext_sessions_getRecentlyClosed_private.js]
|
||||
[browser_ext_sessions_getRecentlyClosed_tabs.js]
|
||||
@ -102,6 +104,7 @@ support-files =
|
||||
[browser_ext_tabs_executeScript.js]
|
||||
[browser_ext_tabs_executeScript_good.js]
|
||||
[browser_ext_tabs_executeScript_bad.js]
|
||||
[browser_ext_tabs_executeScript_multiple.js]
|
||||
[browser_ext_tabs_executeScript_no_create.js]
|
||||
[browser_ext_tabs_executeScript_runAt.js]
|
||||
[browser_ext_tabs_getCurrent.js]
|
||||
|
@ -0,0 +1,70 @@
|
||||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_sessions_forget_closed_tab() {
|
||||
function background() {
|
||||
browser.test.onMessage.addListener((msg, windowId, sessionId) => {
|
||||
if (msg === "check-sessions") {
|
||||
browser.sessions.getRecentlyClosed().then(recentlyClosed => {
|
||||
browser.test.sendMessage("recentlyClosed", recentlyClosed);
|
||||
});
|
||||
} else if (msg === "forget-tab") {
|
||||
browser.sessions.forgetClosedTab(windowId, sessionId).then(
|
||||
() => {
|
||||
browser.test.sendMessage("forgot-tab");
|
||||
},
|
||||
error => {
|
||||
browser.test.assertEq(error.message,
|
||||
`Could not find closed tab using sessionId ${sessionId}.`);
|
||||
browser.test.sendMessage("forget-reject");
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
permissions: ["sessions", "tabs"],
|
||||
},
|
||||
background,
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
|
||||
let tabUrl = "http://example.com";
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, tabUrl);
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, tabUrl);
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
|
||||
extension.sendMessage("check-sessions");
|
||||
let recentlyClosed = yield extension.awaitMessage("recentlyClosed");
|
||||
let recentlyClosedLength = recentlyClosed.length;
|
||||
let recentlyClosedTab = recentlyClosed[0].tab;
|
||||
|
||||
// Check that forgetting a tab works properly
|
||||
extension.sendMessage("forget-tab", recentlyClosedTab.windowId,
|
||||
recentlyClosedTab.sessionId);
|
||||
yield extension.awaitMessage("forgot-tab");
|
||||
extension.sendMessage("check-sessions");
|
||||
let remainingClosed = yield extension.awaitMessage("recentlyClosed");
|
||||
is(remainingClosed.length, recentlyClosedLength - 1,
|
||||
"One tab was forgotten.");
|
||||
is(remainingClosed[0].tab.sessionId, recentlyClosed[1].tab.sessionId,
|
||||
"The correct tab was forgotten.");
|
||||
|
||||
// Check that re-forgetting the same tab fails properly
|
||||
extension.sendMessage("forget-tab", recentlyClosedTab.windowId,
|
||||
recentlyClosedTab.sessionId);
|
||||
yield extension.awaitMessage("forget-reject");
|
||||
extension.sendMessage("check-sessions");
|
||||
remainingClosed = yield extension.awaitMessage("recentlyClosed");
|
||||
is(remainingClosed.length, recentlyClosedLength - 1,
|
||||
"No extra tab was forgotten.");
|
||||
is(remainingClosed[0].tab.sessionId, recentlyClosed[1].tab.sessionId,
|
||||
"The correct tab remains.");
|
||||
|
||||
yield extension.unload();
|
||||
});
|
@ -0,0 +1,72 @@
|
||||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_sessions_forget_closed_window() {
|
||||
function* openAndCloseWindow(url = "http://example.com") {
|
||||
let win = yield BrowserTestUtils.openNewBrowserWindow();
|
||||
yield BrowserTestUtils.loadURI(win.gBrowser.selectedBrowser, url);
|
||||
yield BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
|
||||
yield BrowserTestUtils.closeWindow(win);
|
||||
}
|
||||
|
||||
function background() {
|
||||
browser.test.onMessage.addListener((msg, sessionId) => {
|
||||
if (msg === "check-sessions") {
|
||||
browser.sessions.getRecentlyClosed().then(recentlyClosed => {
|
||||
browser.test.sendMessage("recentlyClosed", recentlyClosed);
|
||||
});
|
||||
} else if (msg === "forget-window") {
|
||||
browser.sessions.forgetClosedWindow(sessionId).then(
|
||||
() => {
|
||||
browser.test.sendMessage("forgot-window");
|
||||
},
|
||||
error => {
|
||||
browser.test.assertEq(error.message,
|
||||
`Could not find closed window using sessionId ${sessionId}.`);
|
||||
browser.test.sendMessage("forget-reject");
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
permissions: ["sessions", "tabs"],
|
||||
},
|
||||
background,
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
|
||||
yield openAndCloseWindow("about:config");
|
||||
yield openAndCloseWindow("about:robots");
|
||||
|
||||
extension.sendMessage("check-sessions");
|
||||
let recentlyClosed = yield extension.awaitMessage("recentlyClosed");
|
||||
let recentlyClosedLength = recentlyClosed.length;
|
||||
let recentlyClosedWindow = recentlyClosed[0].window;
|
||||
|
||||
// Check that forgetting a window works properly
|
||||
extension.sendMessage("forget-window", recentlyClosedWindow.sessionId);
|
||||
yield extension.awaitMessage("forgot-window");
|
||||
extension.sendMessage("check-sessions");
|
||||
let remainingClosed = yield extension.awaitMessage("recentlyClosed");
|
||||
is(remainingClosed.length, recentlyClosedLength - 1,
|
||||
"One window was forgotten.");
|
||||
is(remainingClosed[0].window.sessionId, recentlyClosed[1].window.sessionId,
|
||||
"The correct window was forgotten.");
|
||||
|
||||
// Check that re-forgetting the same window fails properly
|
||||
extension.sendMessage("forget-window", recentlyClosedWindow.sessionId);
|
||||
yield extension.awaitMessage("forget-reject");
|
||||
extension.sendMessage("check-sessions");
|
||||
remainingClosed = yield extension.awaitMessage("recentlyClosed");
|
||||
is(remainingClosed.length, recentlyClosedLength - 1,
|
||||
"No extra window was forgotten.");
|
||||
is(remainingClosed[0].window.sessionId, recentlyClosed[1].window.sessionId,
|
||||
"The correct window remains.");
|
||||
|
||||
yield extension.unload();
|
||||
});
|
@ -0,0 +1,50 @@
|
||||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
add_task(function* testExecuteScript() {
|
||||
const BASE = "http://mochi.test:8888/browser/browser/components/extensions/test/browser/";
|
||||
const URL = BASE + "file_dummy.html";
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, URL, true);
|
||||
|
||||
async function background() {
|
||||
try {
|
||||
await browser.tabs.executeScript({code: "this.foo = 'bar'"});
|
||||
await browser.tabs.executeScript({file: "script.js"});
|
||||
|
||||
let [result1] = await browser.tabs.executeScript({code: "[this.foo, this.bar]"});
|
||||
let [result2] = await browser.tabs.executeScript({file: "script2.js"});
|
||||
|
||||
browser.test.assertEq("bar,baz", String(result1), "executeScript({code}) result");
|
||||
browser.test.assertEq("bar,baz", String(result2), "executeScript({file}) result");
|
||||
|
||||
browser.test.notifyPass("executeScript-multiple");
|
||||
} catch (e) {
|
||||
browser.test.fail(`Error: ${e} :: ${e.stack}`);
|
||||
browser.test.notifyFail("executeScript-multiple");
|
||||
}
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"permissions": ["http://mochi.test/"],
|
||||
},
|
||||
|
||||
background,
|
||||
|
||||
files: {
|
||||
"script.js": function() {
|
||||
this.bar = "baz";
|
||||
},
|
||||
|
||||
"script2.js": "[this.foo, this.bar]",
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
|
||||
yield extension.awaitFinish("executeScript-multiple");
|
||||
|
||||
yield extension.unload();
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
});
|
@ -142,6 +142,25 @@ protected:
|
||||
|
||||
virtual bool IncludeInContext(nsINode *aNode);
|
||||
|
||||
class MOZ_STACK_CLASS AutoReleaseDocumentIfNeeded final
|
||||
{
|
||||
public:
|
||||
explicit AutoReleaseDocumentIfNeeded(nsDocumentEncoder* aEncoder)
|
||||
: mEncoder(aEncoder)
|
||||
{
|
||||
}
|
||||
|
||||
~AutoReleaseDocumentIfNeeded()
|
||||
{
|
||||
if (mEncoder->mFlags & RequiresReinitAfterOutput) {
|
||||
mEncoder->mDocument = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsDocumentEncoder* mEncoder;
|
||||
};
|
||||
|
||||
nsCOMPtr<nsIDocument> mDocument;
|
||||
nsCOMPtr<nsISelection> mSelection;
|
||||
RefPtr<nsRange> mRange;
|
||||
@ -1009,6 +1028,8 @@ nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
|
||||
if (!mDocument)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
AutoReleaseDocumentIfNeeded autoReleaseDocument(this);
|
||||
|
||||
aOutputString.Truncate();
|
||||
|
||||
nsString output;
|
||||
|
@ -5507,7 +5507,7 @@ nsGlobalWindow::GetInnerSize(CSSIntSize& aSize)
|
||||
{
|
||||
MOZ_ASSERT(IsOuterWindow());
|
||||
|
||||
EnsureSizeUpToDate();
|
||||
EnsureSizeAndPositionUpToDate();
|
||||
|
||||
NS_ENSURE_STATE(mDocShell);
|
||||
|
||||
@ -5983,10 +5983,7 @@ nsGlobalWindow::GetInnerScreenRect()
|
||||
return nsRect();
|
||||
}
|
||||
|
||||
nsGlobalWindow* rootWindow = nsGlobalWindow::Cast(GetPrivateRoot());
|
||||
if (rootWindow) {
|
||||
rootWindow->FlushPendingNotifications(FlushType::Layout);
|
||||
}
|
||||
EnsureSizeAndPositionUpToDate();
|
||||
|
||||
if (!mDocShell) {
|
||||
return nsRect();
|
||||
@ -6463,7 +6460,7 @@ nsGlobalWindow::GetScrollXY(bool aDoFlush)
|
||||
if (aDoFlush) {
|
||||
FlushPendingNotifications(FlushType::Layout);
|
||||
} else {
|
||||
EnsureSizeUpToDate();
|
||||
EnsureSizeAndPositionUpToDate();
|
||||
}
|
||||
|
||||
nsIScrollableFrame *sf = GetScrollFrame();
|
||||
@ -13221,7 +13218,7 @@ nsGlobalWindow::FlushPendingNotifications(FlushType aType)
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindow::EnsureSizeUpToDate()
|
||||
nsGlobalWindow::EnsureSizeAndPositionUpToDate()
|
||||
{
|
||||
MOZ_ASSERT(IsOuterWindow());
|
||||
|
||||
|
@ -423,7 +423,7 @@ public:
|
||||
bool aOriginalOpener) override;
|
||||
|
||||
// Outer windows only.
|
||||
virtual void EnsureSizeUpToDate() override;
|
||||
virtual void EnsureSizeAndPositionUpToDate() override;
|
||||
|
||||
virtual void EnterModalState() override;
|
||||
virtual void LeaveModalState() override;
|
||||
|
@ -247,6 +247,13 @@ interface nsIDocumentEncoder : nsISupports
|
||||
*/
|
||||
const unsigned long OutputDisallowLineBreaking = (1 << 27);
|
||||
|
||||
/**
|
||||
* Release reference of nsIDocument after using encodeTo* method to recycle
|
||||
* this encoder without holding nsIDocument. To use this encoder again,
|
||||
* we have to call init again.
|
||||
*/
|
||||
const unsigned long RequiresReinitAfterOutput = (1 << 28);
|
||||
|
||||
/**
|
||||
* Initialize with a pointer to the document and the mime type.
|
||||
* @param aDocument Document to encode.
|
||||
|
@ -313,7 +313,12 @@ public:
|
||||
virtual void SetOpenerWindow(nsPIDOMWindowOuter* aOpener,
|
||||
bool aOriginalOpener) = 0;
|
||||
|
||||
virtual void EnsureSizeUpToDate() = 0;
|
||||
/**
|
||||
* Ensure the size and position of this window are up-to-date by doing
|
||||
* a layout flush in the parent (which will in turn, do a layout flush
|
||||
* in its parent, etc.).
|
||||
*/
|
||||
virtual void EnsureSizeAndPositionUpToDate() = 0;
|
||||
|
||||
/**
|
||||
* Callback for notifying a window about a modal dialog being
|
||||
|
@ -629,6 +629,7 @@ skip-if = toolkit == 'android' || e10s # showmodaldialog
|
||||
[test_element_closest.html]
|
||||
[test_elementTraversal.html]
|
||||
[test_encodeToStringWithMaxLength.html]
|
||||
[test_encodeToStringWithRequiresReinitAfterOutput.html]
|
||||
[test_error.html]
|
||||
[test_EventSource_redirects.html]
|
||||
[test_explicit_user_agent.html]
|
||||
|
@ -0,0 +1,101 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1352882
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1352882 - RequiresReinitAfterOutput</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript">
|
||||
function getEncoder() {
|
||||
const de = SpecialPowers.Ci.nsIDocumentEncoder;
|
||||
const Cc = SpecialPowers.Cc;
|
||||
|
||||
// Create a plaintext encoder without flags.
|
||||
var encoder = Cc["@mozilla.org/layout/documentEncoder;1?type=text/plain"]
|
||||
.createInstance(de);
|
||||
encoder.init(document, "text/plain", encoder.RequiresReinitAfterOutput);
|
||||
return encoder;
|
||||
}
|
||||
|
||||
function testPlaintextSerializerWithRequiresReinitAfterOutput() {
|
||||
var encoder = getEncoder();
|
||||
|
||||
var str = encoder.encodeToString();
|
||||
ok(str, "encodingToString should be successful");
|
||||
|
||||
SimpleTest.doesThrow(() => {
|
||||
encoder.encodeToString();
|
||||
}, 'encodeToString should throw exception if it has RequiresReinitAfterOutput and it is called twice');
|
||||
|
||||
encoder.init(document, "text/plain", encoder.RequiresReinitAfterOutput);
|
||||
str = encoder.encodeToString();
|
||||
ok(str, "encodingToString should be successful after calling init again");
|
||||
|
||||
encoder = getEncoder();
|
||||
|
||||
str = encoder.encodeToStringWithMaxLength(1000);
|
||||
ok(str, "encodingToString should be successful");
|
||||
|
||||
SimpleTest.doesThrow(() => {
|
||||
encoder.encodeToStringWithMaxLength(1000);
|
||||
}, 'encodeToStringWithMaxLength should throw exception if it has RequiresReinitAfterOutput and it is called twice');
|
||||
|
||||
encoder.init(document, "text/plain", encoder.RequiresReinitAfterOutput);
|
||||
str = encoder.encodeToStringWithMaxLength(1000);
|
||||
ok(str, "encodingToStringWithMaxLength should be successful after calling init again");
|
||||
|
||||
encoder = getEncoder();
|
||||
var stream = {
|
||||
close: function() {
|
||||
},
|
||||
|
||||
flush: function() {
|
||||
},
|
||||
|
||||
write: function(buffer, length) {
|
||||
return length;
|
||||
},
|
||||
|
||||
writeFrom: function(buffer, length) {
|
||||
return length;
|
||||
},
|
||||
};
|
||||
|
||||
encoder.setCharset("utf-8");
|
||||
encoder.encodeToStream(stream);
|
||||
ok(str, "encodingToStream should be successful");
|
||||
|
||||
SimpleTest.doesThrow(() => {
|
||||
encoder.encodeToStream(stream);
|
||||
}, 'encodeToStream should throw exception if it has RequiresReinitAfterOutput and it is called twice');
|
||||
|
||||
encoder.init(document, "text/plain", encoder.RequiresReinitAfterOutput);
|
||||
encoder.encodeToStream(stream);
|
||||
ok(true, "encodingToStream should be successful after calling init again");
|
||||
|
||||
stream.close();
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
addLoadEvent(testPlaintextSerializerWithRequiresReinitAfterOutput);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1352882">Mozilla Bug 1352882</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
The <em>Mozilla</em> project is a global community of <strong>people</strong> who believe that openness, innovation, and opportunity are key to the continued health of the Internet. We have worked together since 1998 to ensure that the Internet is developed in a way that benefits everyone. We are best known for creating the Mozilla Firefox web browser.
|
||||
|
||||
The Mozilla project uses a community-based approach to create world-class open source software and to develop new types of collaborative activities. We create communities of people involved in making the Internet experience better for all of us.
|
||||
|
||||
As a result of these efforts, we have distilled a set of principles that we believe are critical for the Internet to continue to benefit the public good as well as commercial aspects of life. We set out these principles below.
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -3801,9 +3801,8 @@ void
|
||||
CanvasRenderingContext2D::EnsureWritablePath()
|
||||
{
|
||||
EnsureTarget();
|
||||
if (!IsTargetValid()) {
|
||||
return;
|
||||
}
|
||||
// NOTE: IsTargetValid() may be false here (mTarget == sErrorTarget) but we
|
||||
// go ahead and create a path anyway since callers depend on that.
|
||||
|
||||
if (mDSPathBuilder) {
|
||||
return;
|
||||
|
10
dom/canvas/crashtests/1357092.html
Normal file
10
dom/canvas/crashtests/1357092.html
Normal file
@ -0,0 +1,10 @@
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
o1 = document.createElement("canvas");
|
||||
o1.setAttribute("width", "100000");
|
||||
o2 = o1.getContext("2d");
|
||||
o2.bezierCurveTo(64, 1, 1, 1, 1, 1);
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
@ -42,4 +42,4 @@ load 1305312-1.html
|
||||
load 1298576-1.html
|
||||
load 1334366-1.html
|
||||
load 1334647-1.html
|
||||
|
||||
load 1357092.html
|
||||
|
@ -337,8 +337,8 @@ DataTransfer::GetTypes(nsTArray<nsString>& aTypes, CallerType aCallerType) const
|
||||
// reasons.
|
||||
nsAutoString type;
|
||||
item->GetInternalType(type);
|
||||
if (item->Kind() == DataTransferItem::KIND_STRING || type.EqualsASCII(kFileMime)) {
|
||||
// If the entry has kind KIND_STRING, we want to add it to the list.
|
||||
if (item->Kind() != DataTransferItem::KIND_FILE || type.EqualsASCII(kFileMime)) {
|
||||
// If the entry has kind KIND_STRING or KIND_OTHER we want to add it to the list.
|
||||
aTypes.AppendElement(type);
|
||||
}
|
||||
}
|
||||
|
@ -315,6 +315,23 @@ function test_DataTransfer(dt)
|
||||
is(dt.mozItemCount, 3, "setDataAt node itemCount");
|
||||
checkOneDataItem(dt, ["application/-moz-node"], ["draggable"], 2, "setDataAt node item at index 2");
|
||||
|
||||
// Try to add and then remove a non-string type to the DataTransfer and ensure
|
||||
// that the type appears in DataTransfer.types. These calls need to be called
|
||||
// with SpecialPowers.wrap(), as adding and removing non-string/file types to
|
||||
// DataTransfer is chrome-only.
|
||||
{
|
||||
SpecialPowers.wrap(dt).mozSetDataAt("application/-x-body", document.body, 0);
|
||||
let found = false;
|
||||
for (let i = 0; i < dt.types.length; ++i) {
|
||||
if (dt.types[i] == "application/-x-body") {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ok(found, "Data should appear in datatransfer.types despite having a non-string type");
|
||||
SpecialPowers.wrap(dt).mozClearDataAt("application/-x-body", 0);
|
||||
}
|
||||
|
||||
dt.mozClearDataAt("text/html", 1);
|
||||
is(dt.mozItemCount, 3, "clearDataAt itemCount");
|
||||
checkOneDataItem(dt, ["text/plain", "text/html"],
|
||||
|
@ -268,7 +268,6 @@ VRPose::VRPose(nsISupports* aParent)
|
||||
: Pose(aParent)
|
||||
{
|
||||
mFrameId = 0;
|
||||
mVRState.Clear();
|
||||
mozilla::HoldJSObjects(this);
|
||||
}
|
||||
|
||||
@ -861,7 +860,6 @@ VRFrameInfo::Update(const gfx::VRDisplayInfo& aInfo,
|
||||
VRFrameInfo::VRFrameInfo()
|
||||
: mTimeStampOffset(0.0f)
|
||||
{
|
||||
mVRState.Clear();
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -30,7 +30,6 @@ VRMockDisplay::VRMockDisplay(const nsCString& aID, uint32_t aDeviceID)
|
||||
: mDeviceID(aDeviceID)
|
||||
, mTimestamp(TimeStamp::Now())
|
||||
{
|
||||
mSensorState.Clear();
|
||||
mDisplayInfo.mDisplayName = aID;
|
||||
mDisplayInfo.mType = VRDeviceType::Puppet;
|
||||
mDisplayInfo.mIsConnected = true;
|
||||
|
@ -106,10 +106,12 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(TextEditor, EditorBase)
|
||||
if (tmp->mRules)
|
||||
tmp->mRules->DetachEditor();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRules)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCachedDocumentEncoder)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(TextEditor, EditorBase)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRules)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCachedDocumentEncoder)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(TextEditor, EditorBase)
|
||||
@ -1169,24 +1171,35 @@ TextEditor::CanDelete(bool* aCanDelete)
|
||||
}
|
||||
|
||||
// Shared between OutputToString and OutputToStream
|
||||
nsresult
|
||||
already_AddRefed<nsIDocumentEncoder>
|
||||
TextEditor::GetAndInitDocEncoder(const nsAString& aFormatType,
|
||||
uint32_t aFlags,
|
||||
const nsACString& aCharset,
|
||||
nsIDocumentEncoder** encoder)
|
||||
const nsACString& aCharset)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
nsAutoCString formatType(NS_DOC_ENCODER_CONTRACTID_BASE);
|
||||
LossyAppendUTF16toASCII(aFormatType, formatType);
|
||||
nsCOMPtr<nsIDocumentEncoder> docEncoder (do_CreateInstance(formatType.get(), &rv));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIDocumentEncoder> docEncoder;
|
||||
if (!mCachedDocumentEncoder ||
|
||||
!mCachedDocumentEncoderType.Equals(aFormatType)) {
|
||||
nsAutoCString formatType(NS_DOC_ENCODER_CONTRACTID_BASE);
|
||||
LossyAppendUTF16toASCII(aFormatType, formatType);
|
||||
docEncoder = do_CreateInstance(formatType.get());
|
||||
if (NS_WARN_IF(!docEncoder)) {
|
||||
return nullptr;
|
||||
}
|
||||
mCachedDocumentEncoder = docEncoder;
|
||||
mCachedDocumentEncoderType = aFormatType;
|
||||
} else {
|
||||
docEncoder = mCachedDocumentEncoder;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryReferent(mDocWeak);
|
||||
NS_ASSERTION(domDoc, "Need a document");
|
||||
|
||||
rv = docEncoder->Init(domDoc, aFormatType, aFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsresult rv =
|
||||
docEncoder->Init(domDoc, aFormatType,
|
||||
aFlags | nsIDocumentEncoder::RequiresReinitAfterOutput);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!aCharset.IsEmpty() && !aCharset.EqualsLiteral("null")) {
|
||||
docEncoder->SetCharset(aCharset);
|
||||
@ -1203,23 +1216,30 @@ TextEditor::GetAndInitDocEncoder(const nsAString& aFormatType,
|
||||
// in which case we use our existing selection ...
|
||||
if (aFlags & nsIDocumentEncoder::OutputSelectionOnly) {
|
||||
RefPtr<Selection> selection = GetSelection();
|
||||
NS_ENSURE_STATE(selection);
|
||||
if (NS_WARN_IF(!selection)) {
|
||||
return nullptr;
|
||||
}
|
||||
rv = docEncoder->SetSelection(selection);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
// ... or if the root element is not a body,
|
||||
// in which case we set the selection to encompass the root.
|
||||
else {
|
||||
dom::Element* rootElement = GetRoot();
|
||||
NS_ENSURE_TRUE(rootElement, NS_ERROR_FAILURE);
|
||||
if (NS_WARN_IF(!rootElement)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!rootElement->IsHTMLElement(nsGkAtoms::body)) {
|
||||
rv = docEncoder->SetNativeContainerNode(rootElement);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
docEncoder.forget(encoder);
|
||||
return NS_OK;
|
||||
return docEncoder.forget();
|
||||
}
|
||||
|
||||
|
||||
@ -1254,9 +1274,12 @@ TextEditor::OutputToString(const nsAString& aFormatType,
|
||||
charsetStr.AssignLiteral("ISO-8859-1");
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocumentEncoder> encoder;
|
||||
rv = GetAndInitDocEncoder(aFormatType, aFlags, charsetStr, getter_AddRefs(encoder));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIDocumentEncoder> encoder =
|
||||
GetAndInitDocEncoder(aFormatType, aFlags, charsetStr);
|
||||
if (NS_WARN_IF(!encoder)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return encoder->EncodeToString(aOutputString);
|
||||
}
|
||||
|
||||
@ -1281,11 +1304,11 @@ TextEditor::OutputToStream(nsIOutputStream* aOutputStream,
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocumentEncoder> encoder;
|
||||
rv = GetAndInitDocEncoder(aFormatType, aFlags, aCharset,
|
||||
getter_AddRefs(encoder));
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIDocumentEncoder> encoder =
|
||||
GetAndInitDocEncoder(aFormatType, aFlags, aCharset);
|
||||
if (NS_WARN_IF(!encoder)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return encoder->EncodeToStream(aOutputStream);
|
||||
}
|
||||
|
@ -184,10 +184,10 @@ protected:
|
||||
void BeginEditorInit();
|
||||
nsresult EndEditorInit();
|
||||
|
||||
nsresult GetAndInitDocEncoder(const nsAString& aFormatType,
|
||||
uint32_t aFlags,
|
||||
const nsACString& aCharset,
|
||||
nsIDocumentEncoder** encoder);
|
||||
already_AddRefed<nsIDocumentEncoder> GetAndInitDocEncoder(
|
||||
const nsAString& aFormatType,
|
||||
uint32_t aFlags,
|
||||
const nsACString& aCharset);
|
||||
|
||||
NS_IMETHOD CreateBR(nsIDOMNode* aNode, int32_t aOffset,
|
||||
nsCOMPtr<nsIDOMNode>* outBRNode,
|
||||
@ -232,6 +232,8 @@ protected:
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIEditRules> mRules;
|
||||
nsCOMPtr<nsIDocumentEncoder> mCachedDocumentEncoder;
|
||||
nsString mCachedDocumentEncoderType;
|
||||
int32_t mWrapColumn;
|
||||
int32_t mMaxTextLength;
|
||||
int32_t mInitTriggerCounter;
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "FilterNodeSoftware.h"
|
||||
#include "GradientStopsD2D.h"
|
||||
#include "SourceSurfaceD2D1.h"
|
||||
#include "SourceSurfaceDual.h"
|
||||
#include "RadialGradientEffectD2D1.h"
|
||||
|
||||
#include "HelpersD2D.h"
|
||||
@ -1870,6 +1871,21 @@ DrawTargetD2D1::GetImageForSurface(SourceSurface *aSurface, Matrix &aSourceTrans
|
||||
AddDependencyOnSource(surf);
|
||||
}
|
||||
break;
|
||||
case SurfaceType::DUAL_DT:
|
||||
{
|
||||
// Sometimes we have a dual drawtarget but the underlying targets
|
||||
// are d2d surfaces. Let's not readback and reupload in those cases.
|
||||
SourceSurfaceDual* surface = static_cast<SourceSurfaceDual*>(aSurface);
|
||||
SourceSurface* first = surface->GetFirstSurface();
|
||||
if (first->GetType() == SurfaceType::D2D1_1_IMAGE) {
|
||||
MOZ_ASSERT(surface->SameSurfaceTypes());
|
||||
SourceSurfaceD2D1* d2dSurface = static_cast<SourceSurfaceD2D1*>(first);
|
||||
image = d2dSurface->GetImage();
|
||||
AddDependencyOnSource(d2dSurface);
|
||||
break;
|
||||
}
|
||||
// Otherwise fall through
|
||||
}
|
||||
default:
|
||||
{
|
||||
RefPtr<DataSourceSurface> dataSurf = aSurface->GetDataSurface();
|
||||
|
@ -27,12 +27,22 @@ public:
|
||||
virtual IntSize GetSize() const { return mA->GetSize(); }
|
||||
virtual SurfaceFormat GetFormat() const { return mA->GetFormat(); }
|
||||
|
||||
// This is implemented for debugging purposes only (used by dumping
|
||||
// client-side textures for paint dumps), for which we don't care about
|
||||
// component alpha, so we just use the first of the two surfaces.
|
||||
// TODO: This is probably wrong as this was originally only
|
||||
// used for debugging purposes, but now has legacy relying on
|
||||
// giving the first type only.
|
||||
virtual already_AddRefed<DataSourceSurface> GetDataSurface() {
|
||||
return mA->GetDataSurface();
|
||||
}
|
||||
|
||||
SourceSurface* GetFirstSurface() {
|
||||
MOZ_ASSERT(mA->GetType() == mB->GetType());
|
||||
return mA;
|
||||
}
|
||||
|
||||
bool SameSurfaceTypes() {
|
||||
return mA->GetType() == mB->GetType();
|
||||
}
|
||||
|
||||
private:
|
||||
friend class DualSurface;
|
||||
friend class DualPattern;
|
||||
|
@ -1150,17 +1150,19 @@ nsEventStatus AsyncPanZoomController::OnTouchMove(const MultiTouchInput& aEvent)
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
ParentLayerPoint touchPoint = GetFirstTouchPoint(aEvent);
|
||||
|
||||
MOZ_ASSERT(GetCurrentTouchBlock());
|
||||
if (gfxPrefs::TouchActionEnabled() && GetCurrentTouchBlock()->TouchActionAllowsPanningXY()) {
|
||||
// User tries to trigger a touch behavior. If allowed touch behavior is vertical pan
|
||||
// + horizontal pan (touch-action value is equal to AUTO) we can return ConsumeNoDefault
|
||||
// status immediately to trigger cancel event further. It should happen independent of
|
||||
// the parent type (whether it is scrolling or not).
|
||||
StartPanning(aEvent);
|
||||
StartPanning(touchPoint);
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
||||
return StartPanning(aEvent);
|
||||
return StartPanning(touchPoint);
|
||||
}
|
||||
|
||||
case PANNING:
|
||||
@ -1251,43 +1253,9 @@ nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent)
|
||||
case PAN_MOMENTUM:
|
||||
{
|
||||
MOZ_ASSERT(GetCurrentTouchBlock());
|
||||
GetCurrentTouchBlock()->GetOverscrollHandoffChain()->FlushRepaints();
|
||||
mX.EndTouch(aEvent.mTime);
|
||||
mY.EndTouch(aEvent.mTime);
|
||||
ParentLayerPoint flingVelocity = GetVelocityVector();
|
||||
// Clear our velocities; if DispatchFling() gives the fling to us,
|
||||
// the fling velocity gets *added* to our existing velocity in
|
||||
// AcceptFling().
|
||||
mX.SetVelocity(0);
|
||||
mY.SetVelocity(0);
|
||||
// Clear our state so that we don't stay in the PANNING state
|
||||
// if DispatchFling() gives the fling to somone else. However,
|
||||
// don't send the state change notification until we've determined
|
||||
// what our final state is to avoid notification churn.
|
||||
StateChangeNotificationBlocker blocker(this);
|
||||
SetState(NOTHING);
|
||||
|
||||
APZC_LOG("%p starting a fling animation if %f >= %f\n", this,
|
||||
flingVelocity.Length().value, gfxPrefs::APZFlingMinVelocityThreshold());
|
||||
|
||||
if (flingVelocity.Length() < gfxPrefs::APZFlingMinVelocityThreshold()) {
|
||||
// Relieve overscroll now if needed, since we will not transition to a fling
|
||||
// animation and then an overscroll animation, and relieve it then.
|
||||
GetCurrentTouchBlock()->GetOverscrollHandoffChain()->SnapBackOverscrolledApzc(this);
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
||||
// Make a local copy of the tree manager pointer and check that it's not
|
||||
// null before calling DispatchFling(). This is necessary because Destroy(),
|
||||
// which nulls out mTreeManager, could be called concurrently.
|
||||
if (APZCTreeManager* treeManagerLocal = GetApzcTreeManager()) {
|
||||
FlingHandoffState handoffState{flingVelocity,
|
||||
GetCurrentTouchBlock()->GetOverscrollHandoffChain(),
|
||||
false /* not handoff */,
|
||||
GetCurrentTouchBlock()->GetScrolledApzc()};
|
||||
treeManagerLocal->DispatchFling(this, handoffState);
|
||||
}
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
return HandleEndOfPan();
|
||||
}
|
||||
case PINCHING:
|
||||
SetState(NOTHING);
|
||||
@ -1324,6 +1292,13 @@ nsEventStatus AsyncPanZoomController::OnScaleBegin(const PinchGestureInput& aEve
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
// If zooming is not allowed, this is a two-finger pan.
|
||||
// Start tracking panning distance and velocity.
|
||||
if (!mZoomConstraints.mAllowZoom) {
|
||||
mX.StartTouch(aEvent.mLocalFocusPoint.x, aEvent.mTime);
|
||||
mY.StartTouch(aEvent.mLocalFocusPoint.y, aEvent.mTime);
|
||||
}
|
||||
|
||||
// For platforms that don't support APZ zooming, dispatch a message to the
|
||||
// content controller, it may want to do something else with this gesture.
|
||||
if (!gfxPrefs::APZAllowZooming()) {
|
||||
@ -1351,6 +1326,13 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
||||
// If zooming is not allowed, this is a two-finger pan.
|
||||
// Tracking panning distance and velocity.
|
||||
if (!mZoomConstraints.mAllowZoom) {
|
||||
mX.UpdateWithTouchAtDevicePoint(aEvent.mLocalFocusPoint.x, 0, aEvent.mTime);
|
||||
mY.UpdateWithTouchAtDevicePoint(aEvent.mLocalFocusPoint.y, 0, aEvent.mTime);
|
||||
}
|
||||
|
||||
if (!gfxPrefs::APZAllowZooming()) {
|
||||
if (RefPtr<GeckoContentController> controller = GetGeckoContentController()) {
|
||||
controller->NotifyPinchGesture(aEvent.mType, GetGuid(),
|
||||
@ -1477,8 +1459,6 @@ nsEventStatus AsyncPanZoomController::OnScaleEnd(const PinchGestureInput& aEvent
|
||||
}
|
||||
}
|
||||
|
||||
SetState(NOTHING);
|
||||
|
||||
{
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
ScheduleComposite();
|
||||
@ -1488,32 +1468,90 @@ nsEventStatus AsyncPanZoomController::OnScaleEnd(const PinchGestureInput& aEvent
|
||||
|
||||
// Non-negative focus point would indicate that one finger is still down
|
||||
if (aEvent.mLocalFocusPoint.x != -1 && aEvent.mLocalFocusPoint.y != -1) {
|
||||
mPanDirRestricted = false;
|
||||
mX.StartTouch(aEvent.mLocalFocusPoint.x, aEvent.mTime);
|
||||
mY.StartTouch(aEvent.mLocalFocusPoint.y, aEvent.mTime);
|
||||
SetState(TOUCHING);
|
||||
if (mZoomConstraints.mAllowZoom) {
|
||||
mPanDirRestricted = false;
|
||||
mX.StartTouch(aEvent.mLocalFocusPoint.x, aEvent.mTime);
|
||||
mY.StartTouch(aEvent.mLocalFocusPoint.y, aEvent.mTime);
|
||||
SetState(TOUCHING);
|
||||
} else {
|
||||
// If zooming isn't allowed, StartTouch() was already called
|
||||
// in OnScaleBegin().
|
||||
StartPanning(aEvent.mLocalFocusPoint);
|
||||
}
|
||||
} else {
|
||||
// Otherwise, handle the fingers being lifted.
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
if (mZoomConstraints.mAllowZoom) {
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
|
||||
// We can get into a situation where we are overscrolled at the end of a
|
||||
// pinch if we go into overscroll with a two-finger pan, and then turn
|
||||
// that into a pinch by increasing the span sufficiently. In such a case,
|
||||
// there is no snap-back animation to get us out of overscroll, so we need
|
||||
// to get out of it somehow.
|
||||
// Moreover, in cases of scroll handoff, the overscroll can be on an APZC
|
||||
// further up in the handoff chain rather than on the current APZC, so
|
||||
// we need to clear overscroll along the entire handoff chain.
|
||||
if (HasReadyTouchBlock()) {
|
||||
GetCurrentTouchBlock()->GetOverscrollHandoffChain()->ClearOverscroll();
|
||||
// We can get into a situation where we are overscrolled at the end of a
|
||||
// pinch if we go into overscroll with a two-finger pan, and then turn
|
||||
// that into a pinch by increasing the span sufficiently. In such a case,
|
||||
// there is no snap-back animation to get us out of overscroll, so we need
|
||||
// to get out of it somehow.
|
||||
// Moreover, in cases of scroll handoff, the overscroll can be on an APZC
|
||||
// further up in the handoff chain rather than on the current APZC, so
|
||||
// we need to clear overscroll along the entire handoff chain.
|
||||
if (HasReadyTouchBlock()) {
|
||||
GetCurrentTouchBlock()->GetOverscrollHandoffChain()->ClearOverscroll();
|
||||
} else {
|
||||
ClearOverscroll();
|
||||
}
|
||||
// Along with clearing the overscroll, we also want to snap to the nearest
|
||||
// snap point as appropriate.
|
||||
ScrollSnap();
|
||||
} else {
|
||||
ClearOverscroll();
|
||||
// when zoom is not allowed
|
||||
mX.EndTouch(aEvent.mTime);
|
||||
mY.EndTouch(aEvent.mTime);
|
||||
if (mState == PINCHING) {
|
||||
// still pinching
|
||||
if (HasReadyTouchBlock()) {
|
||||
return HandleEndOfPan();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Along with clearing the overscroll, we also want to snap to the nearest
|
||||
// snap point as appropriate.
|
||||
ScrollSnap();
|
||||
}
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
||||
nsEventStatus AsyncPanZoomController::HandleEndOfPan()
|
||||
{
|
||||
MOZ_ASSERT(GetCurrentTouchBlock());
|
||||
GetCurrentTouchBlock()->GetOverscrollHandoffChain()->FlushRepaints();
|
||||
ParentLayerPoint flingVelocity = GetVelocityVector();
|
||||
|
||||
// Clear our velocities; if DispatchFling() gives the fling to us,
|
||||
// the fling velocity gets *added* to our existing velocity in
|
||||
// AcceptFling().
|
||||
mX.SetVelocity(0);
|
||||
mY.SetVelocity(0);
|
||||
// Clear our state so that we don't stay in the PANNING state
|
||||
// if DispatchFling() gives the fling to somone else. However,
|
||||
// don't send the state change notification until we've determined
|
||||
// what our final state is to avoid notification churn.
|
||||
StateChangeNotificationBlocker blocker(this);
|
||||
SetState(NOTHING);
|
||||
|
||||
APZC_LOG("%p starting a fling animation if %f >= %f\n", this,
|
||||
flingVelocity.Length().value, gfxPrefs::APZFlingMinVelocityThreshold());
|
||||
|
||||
if (flingVelocity.Length() < gfxPrefs::APZFlingMinVelocityThreshold()) {
|
||||
// Relieve overscroll now if needed, since we will not transition to a fling
|
||||
// animation and then an overscroll animation, and relieve it then.
|
||||
GetCurrentTouchBlock()->GetOverscrollHandoffChain()->SnapBackOverscrolledApzc(this);
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
||||
// Make a local copy of the tree manager pointer and check that it's not
|
||||
// null before calling DispatchFling(). This is necessary because Destroy(),
|
||||
// which nulls out mTreeManager, could be called concurrently.
|
||||
if (APZCTreeManager* treeManagerLocal = GetApzcTreeManager()) {
|
||||
FlingHandoffState handoffState{flingVelocity,
|
||||
GetCurrentTouchBlock()->GetOverscrollHandoffChain(),
|
||||
false /* not handoff */,
|
||||
GetCurrentTouchBlock()->GetScrolledApzc()};
|
||||
treeManagerLocal->DispatchFling(this, handoffState);
|
||||
}
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
||||
@ -2324,12 +2362,12 @@ void AsyncPanZoomController::HandlePanningUpdate(const ScreenPoint& aPanDistance
|
||||
}
|
||||
}
|
||||
|
||||
nsEventStatus AsyncPanZoomController::StartPanning(const MultiTouchInput& aEvent) {
|
||||
nsEventStatus
|
||||
AsyncPanZoomController::StartPanning(const ParentLayerPoint& aStartPoint) {
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
|
||||
ParentLayerPoint point = GetFirstTouchPoint(aEvent);
|
||||
float dx = mX.PanDistance(point.x);
|
||||
float dy = mY.PanDistance(point.y);
|
||||
float dx = mX.PanDistance(aStartPoint.x);
|
||||
float dy = mY.PanDistance(aStartPoint.y);
|
||||
|
||||
double angle = atan2(dy, dx); // range [-pi, pi]
|
||||
angle = fabs(angle); // range [0, pi]
|
||||
|
@ -457,6 +457,7 @@ protected:
|
||||
nsEventStatus OnPanEnd(const PanGestureInput& aEvent);
|
||||
nsEventStatus OnPanMomentumStart(const PanGestureInput& aEvent);
|
||||
nsEventStatus OnPanMomentumEnd(const PanGestureInput& aEvent);
|
||||
nsEventStatus HandleEndOfPan();
|
||||
|
||||
/**
|
||||
* Helper methods for handling scroll wheel events.
|
||||
@ -576,7 +577,7 @@ protected:
|
||||
* Sets up anything needed for panning. This takes us out of the "TOUCHING"
|
||||
* state and starts actually panning us.
|
||||
*/
|
||||
nsEventStatus StartPanning(const MultiTouchInput& aStartPoint);
|
||||
nsEventStatus StartPanning(const ParentLayerPoint& aStartPoint);
|
||||
|
||||
/**
|
||||
* Wrapper for Axis::UpdateWithTouchAtDevicePoint(). Calls this function for
|
||||
|
@ -33,9 +33,6 @@ class AsyncPanZoomController;
|
||||
* the screen. Instead, we generate a PinchGestureInput and send that. If the
|
||||
* touch event is not part of a gesture, we just return nsEventStatus_eIgnore
|
||||
* and AsyncPanZoomController is expected to handle it.
|
||||
*
|
||||
* Android doesn't use this class because it has its own built-in gesture event
|
||||
* listeners that should generally be preferred.
|
||||
*/
|
||||
class GestureEventListener final {
|
||||
public:
|
||||
|
@ -138,7 +138,7 @@ PinchWithPinchInput(const RefPtr<InputReceiver>& aTarget,
|
||||
CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_END,
|
||||
// note: negative values here tell APZC
|
||||
// not to turn the pinch into a pan
|
||||
aFocus, -1.0, -1.0),
|
||||
ScreenIntPoint(-1, -1), 10.0 * aScale, 10.0 * aScale),
|
||||
nullptr);
|
||||
if (aOutEventStatuses) {
|
||||
(*aOutEventStatuses)[2] = actualStatus;
|
||||
|
@ -26,10 +26,6 @@ VRDisplayHost::VRDisplayHost(VRDeviceType aType)
|
||||
mDisplayInfo.mType = aType;
|
||||
mDisplayInfo.mDisplayID = VRSystemManager::AllocateDisplayID();
|
||||
mDisplayInfo.mIsPresenting = false;
|
||||
|
||||
for (int i = 0; i < kMaxLatencyFrames; i++) {
|
||||
mLastSensorState[i].Clear();
|
||||
}
|
||||
}
|
||||
|
||||
VRDisplayHost::~VRDisplayHost()
|
||||
|
@ -190,6 +190,10 @@ struct VRDisplayInfo
|
||||
};
|
||||
|
||||
struct VRHMDSensorState {
|
||||
VRHMDSensorState()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
double timestamp;
|
||||
int32_t inputFrameID;
|
||||
VRDisplayCapabilityFlags flags;
|
||||
|
@ -292,7 +292,6 @@ VRDisplayOSVR::GetSensorState()
|
||||
|
||||
VRHMDSensorState result;
|
||||
OSVR_TimeValue timestamp;
|
||||
result.Clear();
|
||||
|
||||
OSVR_OrientationState orientation;
|
||||
|
||||
|
@ -455,7 +455,6 @@ VRHMDSensorState
|
||||
VRDisplayOculus::GetSensorState(double timeOffset)
|
||||
{
|
||||
VRHMDSensorState result;
|
||||
result.Clear();
|
||||
|
||||
ovrTrackingState state = ovr_GetTrackingState(mSession, timeOffset, true);
|
||||
ovrPoseStatef& pose(state.HeadPose);
|
||||
|
@ -210,7 +210,6 @@ VRDisplayOpenVR::GetSensorState(double timeOffset)
|
||||
mVRCompositor->WaitGetPoses(poses, ::vr::k_unMaxTrackedDeviceCount, nullptr, 0);
|
||||
|
||||
VRHMDSensorState result;
|
||||
result.Clear();
|
||||
|
||||
::vr::Compositor_FrameTiming timing;
|
||||
timing.m_nSize = sizeof(::vr::Compositor_FrameTiming);
|
||||
|
@ -90,8 +90,6 @@ VRDisplayPuppet::VRDisplayPuppet()
|
||||
mDisplayInfo.mSittingToStandingTransform._42 = 0.75f;
|
||||
mDisplayInfo.mSittingToStandingTransform._43 = 0.0f;
|
||||
|
||||
mSensorState.Clear();
|
||||
|
||||
gfx::Quaternion rot;
|
||||
|
||||
mSensorState.flags |= VRDisplayCapabilityFlags::Cap_Orientation;
|
||||
|
@ -594,6 +594,9 @@ platform = notwin
|
||||
[PDocAccessible::GetWindowedPluginIAccessible]
|
||||
description =
|
||||
platform = win
|
||||
[PDocAccessible::SyncTextChangeEvent]
|
||||
description =
|
||||
platform = win
|
||||
|
||||
# CPOWs
|
||||
[PBrowser::RpcMessage]
|
||||
|
@ -269,7 +269,7 @@ public:
|
||||
* whether aSyncObj is a proxy, however there may be a
|
||||
* performance penalty associated with that.
|
||||
*/
|
||||
explicit AsyncInvoker(SyncInterface* aSyncObj, Maybe<bool> aIsProxy = Nothing())
|
||||
explicit AsyncInvoker(SyncInterface* aSyncObj, const Maybe<bool>& aIsProxy = Nothing())
|
||||
: mSyncObj(ResolveIsProxy(aSyncObj, aIsProxy) ? nullptr : aSyncObj)
|
||||
{
|
||||
MOZ_ASSERT(aSyncObj);
|
||||
|
@ -61,7 +61,13 @@ class MOZ_STACK_CLASS BytecodeCompiler
|
||||
bool canLazilyParse();
|
||||
bool createParser();
|
||||
bool createSourceAndParser(const Maybe<uint32_t>& parameterListEnd = Nothing());
|
||||
bool createScript(uint32_t preludeStart = 0);
|
||||
|
||||
// If toString{Start,End} are not explicitly passed, assume the script's
|
||||
// offsets in the source used to parse it are the same as what should be
|
||||
// used to compute its Function.prototype.toString() value.
|
||||
bool createScript();
|
||||
bool createScript(uint32_t toStringStart, uint32_t toStringEnd);
|
||||
|
||||
bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter, SharedContext* sharedContext);
|
||||
bool handleParseFailure(const Directives& newDirectives);
|
||||
bool deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObject environment);
|
||||
@ -292,11 +298,17 @@ BytecodeCompiler::createSourceAndParser(const Maybe<uint32_t>& parameterListEnd
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeCompiler::createScript(uint32_t preludeStart /* = 0 */)
|
||||
BytecodeCompiler::createScript()
|
||||
{
|
||||
return createScript(0, sourceBuffer.length());
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeCompiler::createScript(uint32_t toStringStart, uint32_t toStringEnd)
|
||||
{
|
||||
script = JSScript::Create(cx, options,
|
||||
sourceObject, /* sourceStart = */ 0, sourceBuffer.length(),
|
||||
preludeStart);
|
||||
toStringStart, toStringEnd);
|
||||
return script != nullptr;
|
||||
}
|
||||
|
||||
@ -508,7 +520,7 @@ BytecodeCompiler::compileStandaloneFunction(MutableHandleFunction fun,
|
||||
if (fn->pn_funbox->function()->isInterpreted()) {
|
||||
MOZ_ASSERT(fun == fn->pn_funbox->function());
|
||||
|
||||
if (!createScript(fn->pn_funbox->preludeStart))
|
||||
if (!createScript(fn->pn_funbox->toStringStart, fn->pn_funbox->toStringEnd))
|
||||
return false;
|
||||
|
||||
Maybe<BytecodeEmitter> emitter;
|
||||
@ -729,7 +741,7 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
|
||||
|
||||
Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
|
||||
lazy->begin(), lazy->end(),
|
||||
lazy->preludeStart()));
|
||||
lazy->toStringStart(), lazy->toStringEnd()));
|
||||
if (!script)
|
||||
return false;
|
||||
|
||||
|
@ -7949,7 +7949,8 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
|
||||
Rooted<JSObject*> sourceObject(cx, script->sourceObject());
|
||||
Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
|
||||
funbox->bufStart, funbox->bufEnd,
|
||||
funbox->preludeStart));
|
||||
funbox->toStringStart,
|
||||
funbox->toStringEnd));
|
||||
if (!script)
|
||||
return false;
|
||||
|
||||
@ -10469,6 +10470,13 @@ BytecodeEmitter::emitClass(ParseNode* pn)
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// In the case of default class constructors, emit the start and end
|
||||
// offsets in the source buffer as source notes so that when we
|
||||
// actually make the constructor during execution, we can give it the
|
||||
// correct toString output.
|
||||
if (!newSrcNote3(SRC_CLASS_SPAN, ptrdiff_t(pn->pn_pos.begin), ptrdiff_t(pn->pn_pos.end)))
|
||||
return false;
|
||||
|
||||
JSAtom *name = names ? names->innerBinding()->pn_atom : cx->names().empty;
|
||||
if (heritageExpression) {
|
||||
if (!emitAtomOp(name, JSOP_DERIVEDCONSTRUCTOR))
|
||||
|
@ -323,8 +323,10 @@ class FullParseHandler
|
||||
return literal;
|
||||
}
|
||||
|
||||
ParseNode* newClass(ParseNode* name, ParseNode* heritage, ParseNode* methodBlock) {
|
||||
return new_<ClassNode>(name, heritage, methodBlock);
|
||||
ParseNode* newClass(ParseNode* name, ParseNode* heritage, ParseNode* methodBlock,
|
||||
const TokenPos& pos)
|
||||
{
|
||||
return new_<ClassNode>(name, heritage, methodBlock, pos);
|
||||
}
|
||||
ParseNode* newClassMethodList(uint32_t begin) {
|
||||
return new_<ListNode>(PNK_CLASSMETHODLIST, TokenPos(begin, begin + 1));
|
||||
|
@ -1311,8 +1311,9 @@ struct ClassNames : public BinaryNode {
|
||||
};
|
||||
|
||||
struct ClassNode : public TernaryNode {
|
||||
ClassNode(ParseNode* names, ParseNode* heritage, ParseNode* methodsOrBlock)
|
||||
: TernaryNode(PNK_CLASS, JSOP_NOP, names, heritage, methodsOrBlock)
|
||||
ClassNode(ParseNode* names, ParseNode* heritage, ParseNode* methodsOrBlock,
|
||||
const TokenPos& pos)
|
||||
: TernaryNode(PNK_CLASS, JSOP_NOP, names, heritage, methodsOrBlock, pos)
|
||||
{
|
||||
MOZ_ASSERT_IF(names, names->is<ClassNames>());
|
||||
MOZ_ASSERT(methodsOrBlock->is<LexicalScopeNode>() ||
|
||||
|
@ -142,7 +142,8 @@ StatementKindIsBraced(StatementKind kind)
|
||||
kind == StatementKind::Switch ||
|
||||
kind == StatementKind::Try ||
|
||||
kind == StatementKind::Catch ||
|
||||
kind == StatementKind::Finally;
|
||||
kind == StatementKind::Finally ||
|
||||
kind == StatementKind::Class;
|
||||
}
|
||||
|
||||
void
|
||||
@ -458,7 +459,7 @@ UsedNameTracker::rewind(RewindToken token)
|
||||
}
|
||||
|
||||
FunctionBox::FunctionBox(JSContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead,
|
||||
JSFunction* fun, uint32_t preludeStart,
|
||||
JSFunction* fun, uint32_t toStringStart,
|
||||
Directives directives, bool extraWarnings,
|
||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind)
|
||||
: ObjectBox(fun, traceListHead),
|
||||
@ -472,7 +473,8 @@ FunctionBox::FunctionBox(JSContext* cx, LifoAlloc& alloc, ObjectBox* traceListHe
|
||||
bufEnd(0),
|
||||
startLine(1),
|
||||
startColumn(0),
|
||||
preludeStart(preludeStart),
|
||||
toStringStart(toStringStart),
|
||||
toStringEnd(0),
|
||||
length(0),
|
||||
generatorKindBits_(GeneratorKindAsBits(generatorKind)),
|
||||
asyncKindBits_(AsyncKindAsBits(asyncKind)),
|
||||
@ -543,10 +545,16 @@ FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing, FunctionSynt
|
||||
allowNewTarget_ = true;
|
||||
allowSuperProperty_ = fun->allowSuperProperty();
|
||||
|
||||
if (kind == DerivedClassConstructor) {
|
||||
setDerivedClassConstructor();
|
||||
allowSuperCall_ = true;
|
||||
needsThisTDZChecks_ = true;
|
||||
if (kind == ClassConstructor || kind == DerivedClassConstructor) {
|
||||
auto stmt = enclosing->findInnermostStatement<ParseContext::ClassStatement>();
|
||||
MOZ_ASSERT(stmt);
|
||||
stmt->setConstructorBox(this);
|
||||
|
||||
if (kind == DerivedClassConstructor) {
|
||||
setDerivedClassConstructor();
|
||||
allowSuperCall_ = true;
|
||||
needsThisTDZChecks_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isGenexpLambda)
|
||||
@ -566,6 +574,16 @@ FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing, FunctionSynt
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FunctionBox::resetForAbortedSyntaxParse(ParseContext* enclosing, FunctionSyntaxKind kind)
|
||||
{
|
||||
if (kind == ClassConstructor || kind == DerivedClassConstructor) {
|
||||
auto stmt = enclosing->findInnermostStatement<ParseContext::ClassStatement>();
|
||||
MOZ_ASSERT(stmt);
|
||||
stmt->clearConstructorBoxForAbortedSyntaxParse(this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FunctionBox::initWithEnclosingScope(Scope* enclosingScope)
|
||||
{
|
||||
@ -892,7 +910,7 @@ ParserBase::newObjectBox(JSObject* obj)
|
||||
|
||||
template <typename ParseHandler>
|
||||
FunctionBox*
|
||||
Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun, uint32_t preludeStart,
|
||||
Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun, uint32_t toStringStart,
|
||||
Directives inheritedDirectives,
|
||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
|
||||
bool tryAnnexB)
|
||||
@ -908,7 +926,7 @@ Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun, uint32_t preludeS
|
||||
* function.
|
||||
*/
|
||||
FunctionBox* funbox =
|
||||
alloc.new_<FunctionBox>(context, alloc, traceListHead, fun, preludeStart,
|
||||
alloc.new_<FunctionBox>(context, alloc, traceListHead, fun, toStringStart,
|
||||
inheritedDirectives, options().extraWarningsOption,
|
||||
generatorKind, asyncKind);
|
||||
if (!funbox) {
|
||||
@ -2433,7 +2451,7 @@ Parser<SyntaxParseHandler>::finishFunction(bool isStandaloneFunction /* = false
|
||||
LazyScript* lazy = LazyScript::Create(context, fun, pc->closedOverBindingsForLazy(),
|
||||
pc->innerFunctionsForLazy, versionNumber(),
|
||||
funbox->bufStart, funbox->bufEnd,
|
||||
funbox->preludeStart,
|
||||
funbox->toStringStart,
|
||||
funbox->startLine, funbox->startColumn);
|
||||
if (!lazy)
|
||||
return false;
|
||||
@ -2523,7 +2541,7 @@ Parser<FullParseHandler>::standaloneFunction(HandleFunction fun,
|
||||
return null();
|
||||
fn->pn_body = argsbody;
|
||||
|
||||
FunctionBox* funbox = newFunctionBox(fn, fun, /* preludeStart = */ 0, inheritedDirectives,
|
||||
FunctionBox* funbox = newFunctionBox(fn, fun, /* toStringStart = */ 0, inheritedDirectives,
|
||||
generatorKind, asyncKind, /* tryAnnexB = */ false);
|
||||
if (!funbox)
|
||||
return null();
|
||||
@ -3185,7 +3203,7 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
|
||||
|
||||
template <>
|
||||
bool
|
||||
Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, uint32_t preludeStart,
|
||||
Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, uint32_t toStringStart,
|
||||
FunctionSyntaxKind kind, bool tryAnnexB)
|
||||
{
|
||||
// When a lazily-parsed function is called, we only fully parse (and emit)
|
||||
@ -3195,7 +3213,7 @@ Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, uint32_t preludeS
|
||||
|
||||
RootedFunction fun(context, handler.nextLazyInnerFunction());
|
||||
MOZ_ASSERT(!fun->isLegacyGenerator());
|
||||
FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, Directives(/* strict = */ false),
|
||||
FunctionBox* funbox = newFunctionBox(pn, fun, toStringStart, Directives(/* strict = */ false),
|
||||
fun->generatorKind(), fun->asyncKind(), tryAnnexB);
|
||||
if (!funbox)
|
||||
return false;
|
||||
@ -3232,7 +3250,7 @@ Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, uint32_t preludeS
|
||||
|
||||
template <>
|
||||
bool
|
||||
Parser<SyntaxParseHandler>::skipLazyInnerFunction(Node pn, uint32_t preludeStart,
|
||||
Parser<SyntaxParseHandler>::skipLazyInnerFunction(Node pn, uint32_t toStringStart,
|
||||
FunctionSyntaxKind kind, bool tryAnnexB)
|
||||
{
|
||||
MOZ_CRASH("Cannot skip lazy inner functions when syntax parsing");
|
||||
@ -3309,7 +3327,7 @@ Parser<ParseHandler>::templateLiteral(YieldHandling yieldHandling)
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::functionDefinition(Node pn, uint32_t preludeStart,
|
||||
Parser<ParseHandler>::functionDefinition(Node pn, uint32_t toStringStart,
|
||||
InHandling inHandling,
|
||||
YieldHandling yieldHandling, HandleAtom funName,
|
||||
FunctionSyntaxKind kind,
|
||||
@ -3322,7 +3340,7 @@ Parser<ParseHandler>::functionDefinition(Node pn, uint32_t preludeStart,
|
||||
// functions, which are also lazy. Instead, their free variables and
|
||||
// source extents are recorded and may be skipped.
|
||||
if (handler.canSkipLazyInnerFunctions()) {
|
||||
if (!skipLazyInnerFunction(pn, preludeStart, kind, tryAnnexB))
|
||||
if (!skipLazyInnerFunction(pn, toStringStart, kind, tryAnnexB))
|
||||
return null();
|
||||
return pn;
|
||||
}
|
||||
@ -3355,7 +3373,7 @@ Parser<ParseHandler>::functionDefinition(Node pn, uint32_t preludeStart,
|
||||
// reparse a function due to failed syntax parsing and encountering new
|
||||
// "use foo" directives.
|
||||
while (true) {
|
||||
if (trySyntaxParseInnerFunction(pn, fun, preludeStart, inHandling, yieldHandling, kind,
|
||||
if (trySyntaxParseInnerFunction(pn, fun, toStringStart, inHandling, yieldHandling, kind,
|
||||
generatorKind, asyncKind, tryAnnexB, directives,
|
||||
&newDirectives))
|
||||
{
|
||||
@ -3384,7 +3402,7 @@ Parser<ParseHandler>::functionDefinition(Node pn, uint32_t preludeStart,
|
||||
template <>
|
||||
bool
|
||||
Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunction fun,
|
||||
uint32_t preludeStart,
|
||||
uint32_t toStringStart,
|
||||
InHandling inHandling,
|
||||
YieldHandling yieldHandling,
|
||||
FunctionSyntaxKind kind,
|
||||
@ -3418,13 +3436,13 @@ Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct
|
||||
// Make a FunctionBox before we enter the syntax parser, because |pn|
|
||||
// still expects a FunctionBox to be attached to it during BCE, and
|
||||
// the syntax parser cannot attach one to it.
|
||||
FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, inheritedDirectives,
|
||||
FunctionBox* funbox = newFunctionBox(pn, fun, toStringStart, inheritedDirectives,
|
||||
generatorKind, asyncKind, tryAnnexB);
|
||||
if (!funbox)
|
||||
return false;
|
||||
funbox->initWithEnclosingParseContext(pc, kind);
|
||||
|
||||
if (!parser->innerFunction(SyntaxParseHandler::NodeGeneric, pc, funbox, preludeStart,
|
||||
if (!parser->innerFunction(SyntaxParseHandler::NodeGeneric, pc, funbox, toStringStart,
|
||||
inHandling, yieldHandling, kind,
|
||||
inheritedDirectives, newDirectives))
|
||||
{
|
||||
@ -3434,6 +3452,7 @@ Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct
|
||||
// correctness.
|
||||
parser->clearAbortedSyntaxParse();
|
||||
usedNames.rewind(token);
|
||||
funbox->resetForAbortedSyntaxParse(pc, kind);
|
||||
MOZ_ASSERT_IF(!parser->context->helperThread(),
|
||||
!parser->context->isExceptionPending());
|
||||
break;
|
||||
@ -3452,14 +3471,14 @@ Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct
|
||||
} while (false);
|
||||
|
||||
// We failed to do a syntax parse above, so do the full parse.
|
||||
return innerFunction(pn, pc, fun, preludeStart, inHandling, yieldHandling, kind,
|
||||
return innerFunction(pn, pc, fun, toStringStart, inHandling, yieldHandling, kind,
|
||||
generatorKind, asyncKind, tryAnnexB, inheritedDirectives, newDirectives);
|
||||
}
|
||||
|
||||
template <>
|
||||
bool
|
||||
Parser<SyntaxParseHandler>::trySyntaxParseInnerFunction(Node pn, HandleFunction fun,
|
||||
uint32_t preludeStart,
|
||||
uint32_t toStringStart,
|
||||
InHandling inHandling,
|
||||
YieldHandling yieldHandling,
|
||||
FunctionSyntaxKind kind,
|
||||
@ -3470,14 +3489,14 @@ Parser<SyntaxParseHandler>::trySyntaxParseInnerFunction(Node pn, HandleFunction
|
||||
Directives* newDirectives)
|
||||
{
|
||||
// This is already a syntax parser, so just parse the inner function.
|
||||
return innerFunction(pn, pc, fun, preludeStart, inHandling, yieldHandling, kind,
|
||||
return innerFunction(pn, pc, fun, toStringStart, inHandling, yieldHandling, kind,
|
||||
generatorKind, asyncKind, tryAnnexB, inheritedDirectives, newDirectives);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
bool
|
||||
Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox,
|
||||
uint32_t preludeStart,
|
||||
uint32_t toStringStart,
|
||||
InHandling inHandling, YieldHandling yieldHandling,
|
||||
FunctionSyntaxKind kind, Directives inheritedDirectives,
|
||||
Directives* newDirectives)
|
||||
@ -3501,7 +3520,7 @@ Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, FunctionBox*
|
||||
template <typename ParseHandler>
|
||||
bool
|
||||
Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun,
|
||||
uint32_t preludeStart,
|
||||
uint32_t toStringStart,
|
||||
InHandling inHandling, YieldHandling yieldHandling,
|
||||
FunctionSyntaxKind kind,
|
||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
|
||||
@ -3513,13 +3532,13 @@ Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, HandleFuncti
|
||||
// parser. In that case, outerpc is a ParseContext from the full parser
|
||||
// instead of the current top of the stack of the syntax parser.
|
||||
|
||||
FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, inheritedDirectives,
|
||||
FunctionBox* funbox = newFunctionBox(pn, fun, toStringStart, inheritedDirectives,
|
||||
generatorKind, asyncKind, tryAnnexB);
|
||||
if (!funbox)
|
||||
return false;
|
||||
funbox->initWithEnclosingParseContext(outerpc, kind);
|
||||
|
||||
return innerFunction(pn, outerpc, funbox, preludeStart, inHandling, yieldHandling, kind,
|
||||
return innerFunction(pn, outerpc, funbox, toStringStart, inHandling, yieldHandling, kind,
|
||||
inheritedDirectives, newDirectives);
|
||||
}
|
||||
|
||||
@ -3555,7 +3574,7 @@ Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, bool strict
|
||||
return null();
|
||||
|
||||
Directives directives(strict);
|
||||
FunctionBox* funbox = newFunctionBox(pn, fun, /* preludeStart = */ 0, directives,
|
||||
FunctionBox* funbox = newFunctionBox(pn, fun, /* toStringStart = */ 0, directives,
|
||||
generatorKind, asyncKind, /* tryAnnexB = */ false);
|
||||
if (!funbox)
|
||||
return null();
|
||||
@ -3725,14 +3744,14 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
|
||||
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::Operand,
|
||||
reportMissingClosing(JSMSG_CURLY_AFTER_BODY,
|
||||
JSMSG_CURLY_OPENED, openedPos));
|
||||
funbox->bufEnd = pos().end;
|
||||
funbox->setEnd(pos().end);
|
||||
} else {
|
||||
#if !JS_HAS_EXPR_CLOSURES
|
||||
MOZ_ASSERT(kind == Arrow);
|
||||
#endif
|
||||
if (tokenStream.hadError())
|
||||
return false;
|
||||
funbox->bufEnd = pos().end;
|
||||
funbox->setEnd(pos().end);
|
||||
if (kind == Statement && !matchOrInsertSemicolonAfterExpression())
|
||||
return false;
|
||||
}
|
||||
@ -3752,7 +3771,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::functionStmt(uint32_t preludeStart, YieldHandling yieldHandling,
|
||||
Parser<ParseHandler>::functionStmt(uint32_t toStringStart, YieldHandling yieldHandling,
|
||||
DefaultHandling defaultHandling, FunctionAsyncKind asyncKind)
|
||||
{
|
||||
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
|
||||
@ -3838,13 +3857,13 @@ Parser<ParseHandler>::functionStmt(uint32_t preludeStart, YieldHandling yieldHan
|
||||
return null();
|
||||
|
||||
YieldHandling newYieldHandling = GetYieldHandling(generatorKind);
|
||||
return functionDefinition(pn, preludeStart, InAllowed, newYieldHandling, name, Statement,
|
||||
return functionDefinition(pn, toStringStart, InAllowed, newYieldHandling, name, Statement,
|
||||
generatorKind, asyncKind, tryAnnexB);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::functionExpr(uint32_t preludeStart, InvokedPrediction invoked,
|
||||
Parser<ParseHandler>::functionExpr(uint32_t toStringStart, InvokedPrediction invoked,
|
||||
FunctionAsyncKind asyncKind)
|
||||
{
|
||||
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
|
||||
@ -3885,7 +3904,7 @@ Parser<ParseHandler>::functionExpr(uint32_t preludeStart, InvokedPrediction invo
|
||||
if (invoked)
|
||||
pn = handler.setLikelyIIFE(pn);
|
||||
|
||||
return functionDefinition(pn, preludeStart, InAllowed, yieldHandling, name, Expression,
|
||||
return functionDefinition(pn, toStringStart, InAllowed, yieldHandling, name, Expression,
|
||||
generatorKind, asyncKind);
|
||||
}
|
||||
|
||||
@ -5413,7 +5432,7 @@ Parser<ParseHandler>::exportVariableStatement(uint32_t begin)
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::exportFunctionDeclaration(uint32_t begin, uint32_t preludeStart,
|
||||
Parser<ParseHandler>::exportFunctionDeclaration(uint32_t begin, uint32_t toStringStart,
|
||||
FunctionAsyncKind asyncKind /* = SyncFunction */)
|
||||
{
|
||||
if (!abortIfSyntaxParser())
|
||||
@ -5421,7 +5440,7 @@ Parser<ParseHandler>::exportFunctionDeclaration(uint32_t begin, uint32_t prelude
|
||||
|
||||
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
|
||||
|
||||
Node kid = functionStmt(preludeStart, YieldIsKeyword, NameRequired, asyncKind);
|
||||
Node kid = functionStmt(toStringStart, YieldIsKeyword, NameRequired, asyncKind);
|
||||
if (!kid)
|
||||
return null();
|
||||
|
||||
@ -5493,7 +5512,7 @@ Parser<ParseHandler>::exportLexicalDeclaration(uint32_t begin, DeclarationKind k
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::exportDefaultFunctionDeclaration(uint32_t begin, uint32_t preludeStart,
|
||||
Parser<ParseHandler>::exportDefaultFunctionDeclaration(uint32_t begin, uint32_t toStringStart,
|
||||
FunctionAsyncKind asyncKind
|
||||
/* = SyncFunction */)
|
||||
{
|
||||
@ -5502,7 +5521,7 @@ Parser<ParseHandler>::exportDefaultFunctionDeclaration(uint32_t begin, uint32_t
|
||||
|
||||
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
|
||||
|
||||
Node kid = functionStmt(preludeStart, YieldIsKeyword, AllowDefaultName, asyncKind);
|
||||
Node kid = functionStmt(toStringStart, YieldIsKeyword, AllowDefaultName, asyncKind);
|
||||
if (!kid)
|
||||
return null();
|
||||
|
||||
@ -5595,9 +5614,9 @@ Parser<ParseHandler>::exportDefault(uint32_t begin)
|
||||
return null();
|
||||
|
||||
if (nextSameLine == TOK_FUNCTION) {
|
||||
uint32_t preludeStart = pos().begin;
|
||||
uint32_t toStringStart = pos().begin;
|
||||
tokenStream.consumeKnownToken(TOK_FUNCTION);
|
||||
return exportDefaultFunctionDeclaration(begin, preludeStart, AsyncFunction);
|
||||
return exportDefaultFunctionDeclaration(begin, toStringStart, AsyncFunction);
|
||||
}
|
||||
|
||||
tokenStream.ungetToken();
|
||||
@ -5651,9 +5670,9 @@ Parser<ParseHandler>::exportDeclaration()
|
||||
return null();
|
||||
|
||||
if (nextSameLine == TOK_FUNCTION) {
|
||||
uint32_t preludeStart = pos().begin;
|
||||
uint32_t toStringStart = pos().begin;
|
||||
tokenStream.consumeKnownToken(TOK_FUNCTION);
|
||||
return exportFunctionDeclaration(begin, preludeStart, AsyncFunction);
|
||||
return exportFunctionDeclaration(begin, toStringStart, AsyncFunction);
|
||||
}
|
||||
|
||||
error(JSMSG_DECLARATION_AFTER_EXPORT);
|
||||
@ -7023,6 +7042,7 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
|
||||
{
|
||||
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_CLASS));
|
||||
|
||||
uint32_t classStartOffset = pos().begin;
|
||||
bool savedStrictness = setLocalStrictMode(true);
|
||||
|
||||
TokenKind tt;
|
||||
@ -7048,16 +7068,20 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
|
||||
tokenStream.ungetToken();
|
||||
}
|
||||
|
||||
// Push a ParseContext::ClassStatement to keep track of the constructor
|
||||
// funbox.
|
||||
ParseContext::ClassStatement classStmt(pc);
|
||||
|
||||
RootedAtom propAtom(context);
|
||||
|
||||
// A named class creates a new lexical scope with a const binding of the
|
||||
// class name.
|
||||
Maybe<ParseContext::Statement> classStmt;
|
||||
Maybe<ParseContext::Scope> classScope;
|
||||
// class name for the "inner name".
|
||||
Maybe<ParseContext::Statement> innerScopeStmt;
|
||||
Maybe<ParseContext::Scope> innerScope;
|
||||
if (name) {
|
||||
classStmt.emplace(pc, StatementKind::Block);
|
||||
classScope.emplace(this);
|
||||
if (!classScope->init(pc))
|
||||
innerScopeStmt.emplace(pc, StatementKind::Block);
|
||||
innerScope.emplace(this);
|
||||
if (!innerScope->init(pc))
|
||||
return null();
|
||||
}
|
||||
|
||||
@ -7084,7 +7108,6 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
|
||||
if (!classMethods)
|
||||
return null();
|
||||
|
||||
bool seenConstructor = false;
|
||||
for (;;) {
|
||||
TokenKind tt;
|
||||
if (!tokenStream.getToken(&tt))
|
||||
@ -7135,16 +7158,17 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
|
||||
propType = PropertyType::GetterNoExpressionClosure;
|
||||
if (propType == PropertyType::Setter)
|
||||
propType = PropertyType::SetterNoExpressionClosure;
|
||||
if (!isStatic && propAtom == context->names().constructor) {
|
||||
|
||||
bool isConstructor = !isStatic && propAtom == context->names().constructor;
|
||||
if (isConstructor) {
|
||||
if (propType != PropertyType::Method) {
|
||||
errorAt(nameOffset, JSMSG_BAD_METHOD_DEF);
|
||||
return null();
|
||||
}
|
||||
if (seenConstructor) {
|
||||
if (classStmt.constructorBox()) {
|
||||
errorAt(nameOffset, JSMSG_DUPLICATE_PROPERTY, "constructor");
|
||||
return null();
|
||||
}
|
||||
seenConstructor = true;
|
||||
propType = hasHeritage ? PropertyType::DerivedConstructor : PropertyType::Constructor;
|
||||
} else if (isStatic && propAtom == context->names().prototype) {
|
||||
errorAt(nameOffset, JSMSG_BAD_METHOD_DEF);
|
||||
@ -7169,7 +7193,12 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
|
||||
if (!tokenStream.isCurrentTokenType(TOK_RB))
|
||||
funName = propAtom;
|
||||
}
|
||||
Node fn = methodDefinition(nameOffset, propType, funName);
|
||||
|
||||
// Calling toString on constructors need to return the source text for
|
||||
// the entire class. The end offset is unknown at this point in
|
||||
// parsing and will be amended when class parsing finishes below.
|
||||
Node fn = methodDefinition(isConstructor ? classStartOffset : nameOffset,
|
||||
propType, funName);
|
||||
if (!fn)
|
||||
return null();
|
||||
|
||||
@ -7180,6 +7209,15 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
|
||||
return null();
|
||||
}
|
||||
|
||||
// Amend the toStringEnd offset for the constructor now that we've
|
||||
// finished parsing the class.
|
||||
uint32_t classEndOffset = pos().end;
|
||||
if (FunctionBox* ctorbox = classStmt.constructorBox()) {
|
||||
if (ctorbox->function()->isInterpretedLazy())
|
||||
ctorbox->function()->lazyScript()->setToStringEnd(classEndOffset);
|
||||
ctorbox->toStringEnd = classEndOffset;
|
||||
}
|
||||
|
||||
Node nameNode = null();
|
||||
Node methodsOrBlock = classMethods;
|
||||
if (name) {
|
||||
@ -7191,15 +7229,15 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
|
||||
if (!innerName)
|
||||
return null();
|
||||
|
||||
Node classBlock = finishLexicalScope(*classScope, classMethods);
|
||||
Node classBlock = finishLexicalScope(*innerScope, classMethods);
|
||||
if (!classBlock)
|
||||
return null();
|
||||
|
||||
methodsOrBlock = classBlock;
|
||||
|
||||
// Pop the inner scope.
|
||||
classScope.reset();
|
||||
classStmt.reset();
|
||||
innerScope.reset();
|
||||
innerScopeStmt.reset();
|
||||
|
||||
Node outerName = null();
|
||||
if (classContext == ClassStatement) {
|
||||
@ -7219,7 +7257,8 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
|
||||
|
||||
MOZ_ALWAYS_TRUE(setLocalStrictMode(savedStrictness));
|
||||
|
||||
return handler.newClass(nameNode, classHeritage, methodsOrBlock);
|
||||
return handler.newClass(nameNode, classHeritage, methodsOrBlock,
|
||||
TokenPos(classStartOffset, classEndOffset));
|
||||
}
|
||||
|
||||
template <class ParseHandler>
|
||||
@ -7562,9 +7601,9 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling,
|
||||
if (!tokenStream.peekTokenSameLine(&nextSameLine))
|
||||
return null();
|
||||
if (nextSameLine == TOK_FUNCTION) {
|
||||
uint32_t preludeStart = pos().begin;
|
||||
uint32_t toStringStart = pos().begin;
|
||||
tokenStream.consumeKnownToken(TOK_FUNCTION);
|
||||
return functionStmt(preludeStart, yieldHandling, NameRequired, AsyncFunction);
|
||||
return functionStmt(toStringStart, yieldHandling, NameRequired, AsyncFunction);
|
||||
}
|
||||
}
|
||||
|
||||
@ -8109,7 +8148,7 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
|
||||
|
||||
if (!tokenStream.getToken(&next, TokenStream::Operand))
|
||||
return null();
|
||||
uint32_t preludeStart = pos().begin;
|
||||
uint32_t toStringStart = pos().begin;
|
||||
tokenStream.ungetToken();
|
||||
|
||||
FunctionAsyncKind asyncKind = SyncFunction;
|
||||
@ -8134,7 +8173,7 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
|
||||
if (!pn)
|
||||
return null();
|
||||
|
||||
Node arrowFunc = functionDefinition(pn, preludeStart, inHandling, yieldHandling, nullptr,
|
||||
Node arrowFunc = functionDefinition(pn, toStringStart, inHandling, yieldHandling, nullptr,
|
||||
Arrow, NotGenerator, asyncKind);
|
||||
if (!arrowFunc)
|
||||
return null();
|
||||
@ -8448,7 +8487,7 @@ Parser<ParseHandler>::generatorComprehensionLambda(unsigned begin)
|
||||
|
||||
// Create box for fun->object early to root it.
|
||||
Directives directives(/* strict = */ outerpc->sc()->strict());
|
||||
FunctionBox* genFunbox = newFunctionBox(genfn, fun, /* preludeStart = */ 0, directives,
|
||||
FunctionBox* genFunbox = newFunctionBox(genfn, fun, /* toStringStart = */ 0, directives,
|
||||
StarGenerator, SyncFunction, /* tryAnnexB = */ false);
|
||||
if (!genFunbox)
|
||||
return null();
|
||||
@ -8484,7 +8523,7 @@ Parser<ParseHandler>::generatorComprehensionLambda(unsigned begin)
|
||||
uint32_t end = pos().end;
|
||||
handler.setBeginPosition(comp, begin);
|
||||
handler.setEndPosition(comp, end);
|
||||
genFunbox->bufEnd = end;
|
||||
genFunbox->setEnd(end);
|
||||
handler.addStatementToList(body, comp);
|
||||
handler.setEndPosition(body, end);
|
||||
handler.setBeginPosition(genfn, begin);
|
||||
@ -9720,7 +9759,7 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::methodDefinition(uint32_t preludeStart, PropertyType propType,
|
||||
Parser<ParseHandler>::methodDefinition(uint32_t toStringStart, PropertyType propType,
|
||||
HandleAtom funName)
|
||||
{
|
||||
FunctionSyntaxKind kind;
|
||||
@ -9776,7 +9815,7 @@ Parser<ParseHandler>::methodDefinition(uint32_t preludeStart, PropertyType propT
|
||||
if (!pn)
|
||||
return null();
|
||||
|
||||
return functionDefinition(pn, preludeStart, InAllowed, yieldHandling, funName, kind,
|
||||
return functionDefinition(pn, toStringStart, InAllowed, yieldHandling, funName, kind,
|
||||
generatorKind, asyncKind);
|
||||
}
|
||||
|
||||
@ -9906,9 +9945,9 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
|
||||
return null();
|
||||
|
||||
if (nextSameLine == TOK_FUNCTION) {
|
||||
uint32_t preludeStart = pos().begin;
|
||||
uint32_t toStringStart = pos().begin;
|
||||
tokenStream.consumeKnownToken(TOK_FUNCTION);
|
||||
return functionExpr(preludeStart, PredictUninvoked, AsyncFunction);
|
||||
return functionExpr(toStringStart, PredictUninvoked, AsyncFunction);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,6 +87,31 @@ class ParseContext : public Nestable<ParseContext>
|
||||
}
|
||||
};
|
||||
|
||||
class ClassStatement : public Statement
|
||||
{
|
||||
FunctionBox* constructorBox_;
|
||||
|
||||
public:
|
||||
explicit ClassStatement(ParseContext* pc)
|
||||
: Statement(pc, StatementKind::Class),
|
||||
constructorBox_(nullptr)
|
||||
{ }
|
||||
|
||||
void clearConstructorBoxForAbortedSyntaxParse(FunctionBox* funbox) {
|
||||
MOZ_ASSERT(constructorBox_ == funbox);
|
||||
constructorBox_ = nullptr;
|
||||
}
|
||||
|
||||
void setConstructorBox(FunctionBox* funbox) {
|
||||
MOZ_ASSERT(!constructorBox_);
|
||||
constructorBox_ = funbox;
|
||||
}
|
||||
|
||||
FunctionBox* constructorBox() const {
|
||||
return constructorBox_;
|
||||
}
|
||||
};
|
||||
|
||||
// The intra-function scope stack.
|
||||
//
|
||||
// Tracks declared and used names within a scope.
|
||||
@ -442,6 +467,11 @@ class ParseContext : public Nestable<ParseContext>
|
||||
return Statement::findNearest<T>(innermostStatement_, predicate);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* findInnermostStatement() {
|
||||
return Statement::findNearest<T>(innermostStatement_);
|
||||
}
|
||||
|
||||
AtomVector& positionalFormalParameterNames() {
|
||||
return *positionalFormalParameterNames_;
|
||||
}
|
||||
@ -542,6 +572,13 @@ ParseContext::Statement::is<ParseContext::LabelStatement>() const
|
||||
return kind_ == StatementKind::Label;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool
|
||||
ParseContext::Statement::is<ParseContext::ClassStatement>() const
|
||||
{
|
||||
return kind_ == StatementKind::Class;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T&
|
||||
ParseContext::Statement::as()
|
||||
@ -1081,7 +1118,7 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
||||
*/
|
||||
Node parse();
|
||||
|
||||
FunctionBox* newFunctionBox(Node fn, JSFunction* fun, uint32_t preludeStart,
|
||||
FunctionBox* newFunctionBox(Node fn, JSFunction* fun, uint32_t toStringStart,
|
||||
Directives directives,
|
||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
|
||||
bool tryAnnexB);
|
||||
@ -1140,7 +1177,7 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
||||
|
||||
// Parse an inner function given an enclosing ParseContext and a
|
||||
// FunctionBox for the inner function.
|
||||
bool innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, uint32_t preludeStart,
|
||||
bool innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, uint32_t toStringStart,
|
||||
InHandling inHandling, YieldHandling yieldHandling,
|
||||
FunctionSyntaxKind kind,
|
||||
Directives inheritedDirectives, Directives* newDirectives);
|
||||
@ -1174,10 +1211,10 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
||||
* Some parsers have two versions: an always-inlined version (with an 'i'
|
||||
* suffix) and a never-inlined version (with an 'n' suffix).
|
||||
*/
|
||||
Node functionStmt(uint32_t preludeStart,
|
||||
Node functionStmt(uint32_t toStringStart,
|
||||
YieldHandling yieldHandling, DefaultHandling defaultHandling,
|
||||
FunctionAsyncKind asyncKind = SyncFunction);
|
||||
Node functionExpr(uint32_t preludeStart, InvokedPrediction invoked = PredictUninvoked,
|
||||
Node functionExpr(uint32_t toStringStart, InvokedPrediction invoked = PredictUninvoked,
|
||||
FunctionAsyncKind asyncKind = SyncFunction);
|
||||
|
||||
Node statementList(YieldHandling yieldHandling);
|
||||
@ -1230,12 +1267,12 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
||||
Node exportBatch(uint32_t begin);
|
||||
bool checkLocalExportNames(Node node);
|
||||
Node exportClause(uint32_t begin);
|
||||
Node exportFunctionDeclaration(uint32_t begin, uint32_t preludeStart,
|
||||
Node exportFunctionDeclaration(uint32_t begin, uint32_t toStringStart,
|
||||
FunctionAsyncKind asyncKind = SyncFunction);
|
||||
Node exportVariableStatement(uint32_t begin);
|
||||
Node exportClassDeclaration(uint32_t begin);
|
||||
Node exportLexicalDeclaration(uint32_t begin, DeclarationKind kind);
|
||||
Node exportDefaultFunctionDeclaration(uint32_t begin, uint32_t preludeStart,
|
||||
Node exportDefaultFunctionDeclaration(uint32_t begin, uint32_t toStringStart,
|
||||
FunctionAsyncKind asyncKind = SyncFunction);
|
||||
Node exportDefaultClassDeclaration(uint32_t begin);
|
||||
Node exportDefaultAssignExpr(uint32_t begin);
|
||||
@ -1328,7 +1365,7 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
||||
bool tryNewTarget(Node& newTarget);
|
||||
bool checkAndMarkSuperScope();
|
||||
|
||||
Node methodDefinition(uint32_t preludeStart, PropertyType propType, HandleAtom funName);
|
||||
Node methodDefinition(uint32_t toStringStart, PropertyType propType, HandleAtom funName);
|
||||
|
||||
/*
|
||||
* Additional JS parsers.
|
||||
@ -1336,7 +1373,7 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
||||
bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind,
|
||||
Node funcpn);
|
||||
|
||||
Node functionDefinition(Node func, uint32_t preludeStart,
|
||||
Node functionDefinition(Node func, uint32_t toStringStart,
|
||||
InHandling inHandling, YieldHandling yieldHandling,
|
||||
HandleAtom name, FunctionSyntaxKind kind,
|
||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
|
||||
@ -1419,14 +1456,14 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
||||
Node newDotGeneratorName();
|
||||
bool declareDotGeneratorName();
|
||||
|
||||
bool skipLazyInnerFunction(Node pn, uint32_t preludeStart, FunctionSyntaxKind kind,
|
||||
bool skipLazyInnerFunction(Node pn, uint32_t toStringStart, FunctionSyntaxKind kind,
|
||||
bool tryAnnexB);
|
||||
bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, uint32_t preludeStart,
|
||||
bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, uint32_t toStringStart,
|
||||
InHandling inHandling, YieldHandling yieldHandling,
|
||||
FunctionSyntaxKind kind,
|
||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB,
|
||||
Directives inheritedDirectives, Directives* newDirectives);
|
||||
bool trySyntaxParseInnerFunction(Node pn, HandleFunction fun, uint32_t preludeStart,
|
||||
bool trySyntaxParseInnerFunction(Node pn, HandleFunction fun, uint32_t toStringStart,
|
||||
InHandling inHandling, YieldHandling yieldHandling,
|
||||
FunctionSyntaxKind kind,
|
||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
|
||||
|
@ -38,6 +38,7 @@ enum class StatementKind : uint8_t
|
||||
ForOfLoop,
|
||||
DoLoop,
|
||||
WhileLoop,
|
||||
Class,
|
||||
|
||||
// Used only by BytecodeEmitter.
|
||||
Spread
|
||||
@ -450,7 +451,8 @@ class FunctionBox : public ObjectBox, public SharedContext
|
||||
uint32_t bufEnd;
|
||||
uint32_t startLine;
|
||||
uint32_t startColumn;
|
||||
uint32_t preludeStart;
|
||||
uint32_t toStringStart;
|
||||
uint32_t toStringEnd;
|
||||
uint16_t length;
|
||||
|
||||
uint8_t generatorKindBits_; /* The GeneratorKind of this function. */
|
||||
@ -480,7 +482,7 @@ class FunctionBox : public ObjectBox, public SharedContext
|
||||
FunctionContextFlags funCxFlags;
|
||||
|
||||
FunctionBox(JSContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead, JSFunction* fun,
|
||||
uint32_t preludeStart, Directives directives, bool extraWarnings,
|
||||
uint32_t toStringStart, Directives directives, bool extraWarnings,
|
||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind);
|
||||
|
||||
MutableHandle<LexicalScope::Data*> namedLambdaBindings() {
|
||||
@ -501,6 +503,7 @@ class FunctionBox : public ObjectBox, public SharedContext
|
||||
void initFromLazyFunction();
|
||||
void initStandaloneFunction(Scope* enclosingScope);
|
||||
void initWithEnclosingParseContext(ParseContext* enclosing, FunctionSyntaxKind kind);
|
||||
void resetForAbortedSyntaxParse(ParseContext* enclosing, FunctionSyntaxKind kind);
|
||||
|
||||
ObjectBox* toObjectBox() override { return this; }
|
||||
JSFunction* function() const { return &object->as<JSFunction>(); }
|
||||
@ -615,6 +618,14 @@ class FunctionBox : public ObjectBox, public SharedContext
|
||||
tokenStream.srcCoords.lineNumAndColumnIndex(bufStart, &startLine, &startColumn);
|
||||
}
|
||||
|
||||
void setEnd(uint32_t end) {
|
||||
// For all functions except class constructors, the buffer and
|
||||
// toString ending positions are the same. Class constructors override
|
||||
// the toString ending position with the end of the class definition.
|
||||
bufEnd = end;
|
||||
toStringEnd = end;
|
||||
}
|
||||
|
||||
void trace(JSTracer* trc) override;
|
||||
};
|
||||
|
||||
|
@ -56,13 +56,14 @@ namespace js {
|
||||
M(SRC_NEXTCASE, "nextcase", 1) /* Distance forward from one CASE in a CONDSWITCH to \
|
||||
the next. */ \
|
||||
M(SRC_ASSIGNOP, "assignop", 0) /* += or another assign-op follows. */ \
|
||||
M(SRC_CLASS_SPAN, "class", 2) /* The starting and ending offsets for the class, used \
|
||||
for toString correctness for default ctors. */ \
|
||||
M(SRC_TRY, "try", 1) /* JSOP_TRY, offset points to goto at the end of the \
|
||||
try block. */ \
|
||||
/* All notes above here are "gettable". See SN_IS_GETTABLE below. */ \
|
||||
M(SRC_COLSPAN, "colspan", 1) /* Number of columns this opcode spans. */ \
|
||||
M(SRC_NEWLINE, "newline", 0) /* Bytecode follows a source newline. */ \
|
||||
M(SRC_SETLINE, "setline", 1) /* A file-absolute source line number note. */ \
|
||||
M(SRC_UNUSED20, "unused20", 0) /* Unused. */ \
|
||||
M(SRC_UNUSED21, "unused21", 0) /* Unused. */ \
|
||||
M(SRC_UNUSED22, "unused22", 0) /* Unused. */ \
|
||||
M(SRC_UNUSED23, "unused23", 0) /* Unused. */ \
|
||||
|
@ -287,7 +287,7 @@ class SyntaxParseHandler
|
||||
Node newObjectLiteral(uint32_t begin) { return NodeUnparenthesizedObject; }
|
||||
Node newClassMethodList(uint32_t begin) { return NodeGeneric; }
|
||||
Node newClassNames(Node outer, Node inner, const TokenPos& pos) { return NodeGeneric; }
|
||||
Node newClass(Node name, Node heritage, Node methodBlock) { return NodeGeneric; }
|
||||
Node newClass(Node name, Node heritage, Node methodBlock, const TokenPos& pos) { return NodeGeneric; }
|
||||
|
||||
Node newNewTarget(Node newHolder, Node targetHolder) { return NodeGeneric; }
|
||||
Node newPosHolder(const TokenPos& pos) { return NodeGeneric; }
|
||||
|
@ -7037,11 +7037,10 @@ JS::DeserializeWasmModule(PRFileDesc* bytecode, PRFileDesc* maybeCompiled,
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS::SetLargeAllocationFailureCallback(JSContext* cx, JS::LargeAllocationFailureCallback lafc,
|
||||
void* data)
|
||||
JS::SetProcessLargeAllocationFailureCallback(JS::LargeAllocationFailureCallback lafc)
|
||||
{
|
||||
cx->runtime()->largeAllocationFailureCallback = lafc;
|
||||
cx->runtime()->largeAllocationFailureCallbackData = data;
|
||||
MOZ_ASSERT(!OnLargeAllocationFailure);
|
||||
OnLargeAllocationFailure = lafc;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
|
@ -6429,16 +6429,17 @@ class MOZ_STACK_CLASS JS_PUBLIC_API(ForOfIterator) {
|
||||
|
||||
/**
|
||||
* If a large allocation fails when calling pod_{calloc,realloc}CanGC, the JS
|
||||
* engine may call the large-allocation- failure callback, if set, to allow the
|
||||
* engine may call the large-allocation-failure callback, if set, to allow the
|
||||
* embedding to flush caches, possibly perform shrinking GCs, etc. to make some
|
||||
* room. The allocation will then be retried (and may still fail.)
|
||||
* room. The allocation will then be retried (and may still fail.) This callback
|
||||
* can be called on any thread and must be set at most once in a process.
|
||||
*/
|
||||
|
||||
typedef void
|
||||
(* LargeAllocationFailureCallback)(void* data);
|
||||
(* LargeAllocationFailureCallback)();
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
SetLargeAllocationFailureCallback(JSContext* cx, LargeAllocationFailureCallback afc, void* data);
|
||||
SetProcessLargeAllocationFailureCallback(LargeAllocationFailureCallback afc);
|
||||
|
||||
/**
|
||||
* Unlike the error reporter, which is only called if the exception for an OOM
|
||||
|
@ -882,7 +882,8 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key)
|
||||
sourceObject,
|
||||
begin,
|
||||
ss->length(),
|
||||
0));
|
||||
0,
|
||||
ss->length()));
|
||||
if (!script || !JSScript::initFunctionPrototype(cx, script, functionProto))
|
||||
return nullptr;
|
||||
|
||||
@ -1019,7 +1020,13 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
|
||||
}
|
||||
|
||||
bool funIsNonArrowLambda = fun->isLambda() && !fun->isArrow();
|
||||
bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin();
|
||||
|
||||
// Default class constructors are self-hosted, but have their source
|
||||
// objects overridden to refer to the span of the class statement or
|
||||
// expression. Non-default class constructors are never self-hosted. So,
|
||||
// all class constructors always have source.
|
||||
bool haveSource = fun->isInterpreted() && (fun->isClassConstructor() ||
|
||||
!fun->isSelfHostedBuiltin());
|
||||
|
||||
// If we're not in pretty mode, put parentheses around lambda functions
|
||||
// so that eval returns lambda, not function statement.
|
||||
@ -1060,7 +1067,7 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
|
||||
};
|
||||
|
||||
if (haveSource) {
|
||||
Rooted<JSFlatString*> src(cx, JSScript::sourceDataWithPrelude(cx, script));
|
||||
Rooted<JSFlatString*> src(cx, JSScript::sourceDataForToString(cx, script));
|
||||
if (!src)
|
||||
return nullptr;
|
||||
|
||||
@ -1080,27 +1087,18 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
bool derived = fun->infallibleIsDefaultClassConstructor(cx);
|
||||
if (derived && fun->isDerivedClassConstructor()) {
|
||||
if (!AppendPrelude() ||
|
||||
!out.append("(...args) {\n ") ||
|
||||
!out.append("super(...args);\n}"))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
if (!AppendPrelude() ||
|
||||
!out.append("() {\n "))
|
||||
return nullptr;
|
||||
// Default class constructors should always haveSource.
|
||||
MOZ_ASSERT(!fun->infallibleIsDefaultClassConstructor(cx));
|
||||
|
||||
if (!derived) {
|
||||
if (!out.append("[native code]"))
|
||||
return nullptr;
|
||||
}
|
||||
if (!AppendPrelude() ||
|
||||
!out.append("() {\n "))
|
||||
return nullptr;
|
||||
|
||||
if (!out.append("\n}"))
|
||||
return nullptr;
|
||||
}
|
||||
if (!out.append("[native code]"))
|
||||
return nullptr;
|
||||
|
||||
if (!out.append("\n}"))
|
||||
return nullptr;
|
||||
}
|
||||
return out.finishString();
|
||||
}
|
||||
|
@ -237,7 +237,8 @@ XDRRelazificationInfo(XDRState<mode>* xdr, HandleFunction fun, HandleScript scri
|
||||
{
|
||||
uint32_t begin = script->sourceStart();
|
||||
uint32_t end = script->sourceEnd();
|
||||
uint32_t preludeStart = script->preludeStart();
|
||||
uint32_t toStringStart = script->toStringStart();
|
||||
uint32_t toStringEnd = script->toStringEnd();
|
||||
uint32_t lineno = script->lineno();
|
||||
uint32_t column = script->column();
|
||||
|
||||
@ -245,7 +246,8 @@ XDRRelazificationInfo(XDRState<mode>* xdr, HandleFunction fun, HandleScript scri
|
||||
packedFields = lazy->packedFields();
|
||||
MOZ_ASSERT(begin == lazy->begin());
|
||||
MOZ_ASSERT(end == lazy->end());
|
||||
MOZ_ASSERT(preludeStart == lazy->preludeStart());
|
||||
MOZ_ASSERT(toStringStart == lazy->toStringStart());
|
||||
MOZ_ASSERT(toStringEnd == lazy->toStringEnd());
|
||||
MOZ_ASSERT(lineno == lazy->lineno());
|
||||
MOZ_ASSERT(column == lazy->column());
|
||||
// We can assert we have no inner functions because we don't
|
||||
@ -260,7 +262,11 @@ XDRRelazificationInfo(XDRState<mode>* xdr, HandleFunction fun, HandleScript scri
|
||||
if (mode == XDR_DECODE) {
|
||||
RootedScriptSource sourceObject(cx, &script->scriptSourceUnwrap());
|
||||
lazy.set(LazyScript::Create(cx, fun, script, enclosingScope, sourceObject,
|
||||
packedFields, begin, end, preludeStart, lineno, column));
|
||||
packedFields, begin, end, toStringStart, lineno, column));
|
||||
if (!lazy)
|
||||
return false;
|
||||
|
||||
lazy->setToStringEnd(toStringEnd);
|
||||
|
||||
// As opposed to XDRLazyScript, we need to restore the runtime bits
|
||||
// of the script, as we are trying to match the fact this function
|
||||
@ -545,7 +551,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope,
|
||||
}
|
||||
}
|
||||
|
||||
script = JSScript::Create(cx, *options, sourceObject, 0, 0, 0);
|
||||
script = JSScript::Create(cx, *options, sourceObject, 0, 0, 0, 0);
|
||||
if (!script)
|
||||
return false;
|
||||
|
||||
@ -634,7 +640,9 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope,
|
||||
return false;
|
||||
if (!xdr->codeUint32(&script->sourceEnd_))
|
||||
return false;
|
||||
if (!xdr->codeUint32(&script->preludeStart_))
|
||||
if (!xdr->codeUint32(&script->toStringStart_))
|
||||
return false;
|
||||
if (!xdr->codeUint32(&script->toStringEnd_))
|
||||
return false;
|
||||
|
||||
if (!xdr->codeUint32(&lineno) ||
|
||||
@ -955,7 +963,8 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope,
|
||||
{
|
||||
uint32_t begin;
|
||||
uint32_t end;
|
||||
uint32_t preludeStart;
|
||||
uint32_t toStringStart;
|
||||
uint32_t toStringEnd;
|
||||
uint32_t lineno;
|
||||
uint32_t column;
|
||||
uint64_t packedFields;
|
||||
@ -969,14 +978,16 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope,
|
||||
|
||||
begin = lazy->begin();
|
||||
end = lazy->end();
|
||||
preludeStart = lazy->preludeStart();
|
||||
toStringStart = lazy->toStringStart();
|
||||
toStringEnd = lazy->toStringEnd();
|
||||
lineno = lazy->lineno();
|
||||
column = lazy->column();
|
||||
packedFields = lazy->packedFields();
|
||||
}
|
||||
|
||||
if (!xdr->codeUint32(&begin) || !xdr->codeUint32(&end) ||
|
||||
!xdr->codeUint32(&preludeStart) ||
|
||||
!xdr->codeUint32(&toStringStart) ||
|
||||
!xdr->codeUint32(&toStringEnd) ||
|
||||
!xdr->codeUint32(&lineno) || !xdr->codeUint32(&column) ||
|
||||
!xdr->codeUint64(&packedFields))
|
||||
{
|
||||
@ -985,9 +996,10 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope,
|
||||
|
||||
if (mode == XDR_DECODE) {
|
||||
lazy.set(LazyScript::Create(cx, fun, nullptr, enclosingScope, sourceObject,
|
||||
packedFields, begin, end, preludeStart, lineno, column));
|
||||
packedFields, begin, end, toStringStart, lineno, column));
|
||||
if (!lazy)
|
||||
return false;
|
||||
lazy->setToStringEnd(toStringEnd);
|
||||
fun->initLazyScript(lazy);
|
||||
}
|
||||
}
|
||||
@ -1031,6 +1043,15 @@ JSScript::setSourceObject(JSObject* object)
|
||||
sourceObject_ = object;
|
||||
}
|
||||
|
||||
void
|
||||
JSScript::setDefaultClassConstructorSpan(JSObject* sourceObject, uint32_t start, uint32_t end)
|
||||
{
|
||||
MOZ_ASSERT(isDefaultClassConstructor());
|
||||
setSourceObject(sourceObject);
|
||||
toStringStart_ = start;
|
||||
toStringEnd_ = end;
|
||||
}
|
||||
|
||||
js::ScriptSourceObject&
|
||||
JSScript::scriptSourceUnwrap() const {
|
||||
return UncheckedUnwrap(sourceObject())->as<ScriptSourceObject>();
|
||||
@ -1459,10 +1480,10 @@ JSScript::sourceData(JSContext* cx, HandleScript script)
|
||||
}
|
||||
|
||||
/* static */ JSFlatString*
|
||||
JSScript::sourceDataWithPrelude(JSContext* cx, HandleScript script)
|
||||
JSScript::sourceDataForToString(JSContext* cx, HandleScript script)
|
||||
{
|
||||
MOZ_ASSERT(script->scriptSource()->hasSourceData());
|
||||
return script->scriptSource()->substring(cx, script->preludeStart(), script->sourceEnd());
|
||||
return script->scriptSource()->substring(cx, script->toStringStart(), script->toStringEnd());
|
||||
}
|
||||
|
||||
UncompressedSourceCache::AutoHoldEntry::AutoHoldEntry()
|
||||
@ -2549,9 +2570,15 @@ JSScript::initCompartment(JSContext* cx)
|
||||
/* static */ JSScript*
|
||||
JSScript::Create(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd,
|
||||
uint32_t preludeStart)
|
||||
uint32_t toStringStart, uint32_t toStringEnd)
|
||||
{
|
||||
// bufStart and bufEnd specify the range of characters parsed by the
|
||||
// Parser to produce this script. toStringStart and toStringEnd specify
|
||||
// the range of characters to be returned for Function.prototype.toString.
|
||||
MOZ_ASSERT(bufStart <= bufEnd);
|
||||
MOZ_ASSERT(toStringStart <= toStringEnd);
|
||||
MOZ_ASSERT(toStringStart <= bufStart);
|
||||
MOZ_ASSERT(toStringEnd >= bufEnd);
|
||||
|
||||
RootedScript script(cx, Allocate<JSScript>(cx));
|
||||
if (!script)
|
||||
@ -2571,7 +2598,8 @@ JSScript::Create(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
script->setSourceObject(sourceObject);
|
||||
script->sourceStart_ = bufStart;
|
||||
script->sourceEnd_ = bufEnd;
|
||||
script->preludeStart_ = preludeStart;
|
||||
script->toStringStart_ = toStringStart;
|
||||
script->toStringEnd_ = toStringEnd;
|
||||
|
||||
#ifdef MOZ_VTUNE
|
||||
script->vtuneMethodId_ = vtune::GenerateUniqueMethodID();
|
||||
@ -3521,7 +3549,7 @@ CreateEmptyScriptForClone(JSContext* cx, HandleScript src)
|
||||
.setVersion(src->getVersion());
|
||||
|
||||
return JSScript::Create(cx, options, sourceObject, src->sourceStart(), src->sourceEnd(),
|
||||
src->preludeStart());
|
||||
src->toStringStart(), src->toStringEnd());
|
||||
}
|
||||
|
||||
JSScript*
|
||||
@ -4074,7 +4102,7 @@ JSScript::formalLivesInArgumentsObject(unsigned argSlot)
|
||||
|
||||
LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields,
|
||||
uint32_t begin, uint32_t end,
|
||||
uint32_t preludeStart, uint32_t lineno, uint32_t column)
|
||||
uint32_t toStringStart, uint32_t lineno, uint32_t column)
|
||||
: script_(nullptr),
|
||||
function_(fun),
|
||||
enclosingScope_(nullptr),
|
||||
@ -4083,11 +4111,13 @@ LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields,
|
||||
packedFields_(packedFields),
|
||||
begin_(begin),
|
||||
end_(end),
|
||||
preludeStart_(preludeStart),
|
||||
toStringStart_(toStringStart),
|
||||
toStringEnd_(end),
|
||||
lineno_(lineno),
|
||||
column_(column)
|
||||
{
|
||||
MOZ_ASSERT(begin <= end);
|
||||
MOZ_ASSERT(toStringStart <= begin);
|
||||
}
|
||||
|
||||
void
|
||||
@ -4133,7 +4163,7 @@ LazyScript::maybeForwardedScriptSource() const
|
||||
/* static */ LazyScript*
|
||||
LazyScript::CreateRaw(JSContext* cx, HandleFunction fun,
|
||||
uint64_t packedFields, uint32_t begin, uint32_t end,
|
||||
uint32_t preludeStart, uint32_t lineno, uint32_t column)
|
||||
uint32_t toStringStart, uint32_t lineno, uint32_t column)
|
||||
{
|
||||
union {
|
||||
PackedView p;
|
||||
@ -4162,7 +4192,7 @@ LazyScript::CreateRaw(JSContext* cx, HandleFunction fun,
|
||||
cx->compartment()->scheduleDelazificationForDebugger();
|
||||
|
||||
return new (res) LazyScript(fun, table.forget(), packed, begin, end,
|
||||
preludeStart, lineno, column);
|
||||
toStringStart, lineno, column);
|
||||
}
|
||||
|
||||
/* static */ LazyScript*
|
||||
@ -4171,7 +4201,7 @@ LazyScript::Create(JSContext* cx, HandleFunction fun,
|
||||
Handle<GCVector<JSFunction*, 8>> innerFunctions,
|
||||
JSVersion version,
|
||||
uint32_t begin, uint32_t end,
|
||||
uint32_t preludeStart, uint32_t lineno, uint32_t column)
|
||||
uint32_t toStringStart, uint32_t lineno, uint32_t column)
|
||||
{
|
||||
union {
|
||||
PackedView p;
|
||||
@ -4195,7 +4225,7 @@ LazyScript::Create(JSContext* cx, HandleFunction fun,
|
||||
p.isDerivedClassConstructor = false;
|
||||
p.needsHomeObject = false;
|
||||
|
||||
LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, preludeStart,
|
||||
LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, toStringStart,
|
||||
lineno, column);
|
||||
if (!res)
|
||||
return nullptr;
|
||||
@ -4217,7 +4247,7 @@ LazyScript::Create(JSContext* cx, HandleFunction fun,
|
||||
HandleScript script, HandleScope enclosingScope,
|
||||
HandleScriptSource sourceObject,
|
||||
uint64_t packedFields, uint32_t begin, uint32_t end,
|
||||
uint32_t preludeStart, uint32_t lineno, uint32_t column)
|
||||
uint32_t toStringStart, uint32_t lineno, uint32_t column)
|
||||
{
|
||||
// Dummy atom which is not a valid property name.
|
||||
RootedAtom dummyAtom(cx, cx->names().comma);
|
||||
@ -4226,7 +4256,7 @@ LazyScript::Create(JSContext* cx, HandleFunction fun,
|
||||
// holding this lazy script.
|
||||
HandleFunction dummyFun = fun;
|
||||
|
||||
LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, preludeStart,
|
||||
LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, toStringStart,
|
||||
lineno, column);
|
||||
if (!res)
|
||||
return nullptr;
|
||||
|
@ -939,19 +939,36 @@ class JSScript : public js::gc::TenuredCell
|
||||
|
||||
uint32_t bodyScopeIndex_; /* index into the scopes array of the body scope */
|
||||
|
||||
// Range of characters in scriptSource which contains this script's source.
|
||||
// each field points the following location.
|
||||
// Range of characters in scriptSource which contains this script's
|
||||
// source, that is, the range used by the Parser to produce this script.
|
||||
//
|
||||
// Most scripted functions have sourceStart_ == toStringStart_ and
|
||||
// sourceEnd_ == toStringEnd_. However, for functions with extra
|
||||
// qualifiers (e.g. generators, async) and for class constructors (which
|
||||
// need to return the entire class source), their values differ.
|
||||
//
|
||||
// Each field points the following locations.
|
||||
//
|
||||
// function * f(a, b) { return a + b; }
|
||||
// ^ ^ ^
|
||||
// | | |
|
||||
// | sourceStart_ sourceEnd_
|
||||
// |
|
||||
// preludeStart_
|
||||
// | |
|
||||
// toStringStart_ toStringEnd_
|
||||
//
|
||||
// And, in the case of class constructors, an additional toStringEnd
|
||||
// offset is used.
|
||||
//
|
||||
// class C { constructor() { this.field = 42; } }
|
||||
// ^ ^ ^ ^
|
||||
// | | | `---------`
|
||||
// | sourceStart_ sourceEnd_ |
|
||||
// | |
|
||||
// toStringStart_ toStringEnd_
|
||||
uint32_t sourceStart_;
|
||||
uint32_t sourceEnd_;
|
||||
uint32_t preludeStart_;
|
||||
uint32_t toStringStart_;
|
||||
uint32_t toStringEnd_;
|
||||
|
||||
#ifdef MOZ_VTUNE
|
||||
// Unique Method ID passed to the VTune profiler, or 0 if unset.
|
||||
@ -1121,7 +1138,7 @@ class JSScript : public js::gc::TenuredCell
|
||||
// instead of private to suppress -Wunused-private-field compiler warnings.
|
||||
protected:
|
||||
#if JS_BITS_PER_WORD == 32
|
||||
uint32_t padding;
|
||||
// Currently no padding is needed.
|
||||
#endif
|
||||
|
||||
//
|
||||
@ -1131,8 +1148,9 @@ class JSScript : public js::gc::TenuredCell
|
||||
public:
|
||||
static JSScript* Create(JSContext* cx,
|
||||
const JS::ReadOnlyCompileOptions& options,
|
||||
js::HandleObject sourceObject, uint32_t sourceStart,
|
||||
uint32_t sourceEnd, uint32_t preludeStart);
|
||||
js::HandleObject sourceObject,
|
||||
uint32_t sourceStart, uint32_t sourceEnd,
|
||||
uint32_t toStringStart, uint32_t toStringEnd);
|
||||
|
||||
void initCompartment(JSContext* cx);
|
||||
|
||||
@ -1283,8 +1301,12 @@ class JSScript : public js::gc::TenuredCell
|
||||
return sourceEnd_;
|
||||
}
|
||||
|
||||
size_t preludeStart() const {
|
||||
return preludeStart_;
|
||||
uint32_t toStringStart() const {
|
||||
return toStringStart_;
|
||||
}
|
||||
|
||||
uint32_t toStringEnd() const {
|
||||
return toStringEnd_;
|
||||
}
|
||||
|
||||
bool noScriptRval() const {
|
||||
@ -1620,7 +1642,7 @@ class JSScript : public js::gc::TenuredCell
|
||||
bool mayReadFrameArgsDirectly();
|
||||
|
||||
static JSFlatString* sourceData(JSContext* cx, JS::HandleScript script);
|
||||
static JSFlatString* sourceDataWithPrelude(JSContext* cx, JS::HandleScript script);
|
||||
static JSFlatString* sourceDataForToString(JSContext* cx, JS::HandleScript script);
|
||||
|
||||
static bool loadSource(JSContext* cx, js::ScriptSource* ss, bool* worked);
|
||||
|
||||
@ -1631,6 +1653,9 @@ class JSScript : public js::gc::TenuredCell
|
||||
js::ScriptSourceObject& scriptSourceUnwrap() const;
|
||||
js::ScriptSource* scriptSource() const;
|
||||
js::ScriptSource* maybeForwardedScriptSource() const;
|
||||
|
||||
void setDefaultClassConstructorSpan(JSObject* sourceObject, uint32_t start, uint32_t end);
|
||||
|
||||
bool mutedErrors() const { return scriptSource()->mutedErrors(); }
|
||||
const char* filename() const { return scriptSource()->filename(); }
|
||||
const char* maybeForwardedFilename() const { return maybeForwardedScriptSource()->filename(); }
|
||||
@ -2058,7 +2083,7 @@ class LazyScript : public gc::TenuredCell
|
||||
// instead of private to suppress -Wunused-private-field compiler warnings.
|
||||
protected:
|
||||
#if JS_BITS_PER_WORD == 32
|
||||
// Currently no padding is needed.
|
||||
uint32_t padding;
|
||||
#endif
|
||||
|
||||
private:
|
||||
@ -2106,14 +2131,15 @@ class LazyScript : public gc::TenuredCell
|
||||
// See the comment in JSScript for the details
|
||||
uint32_t begin_;
|
||||
uint32_t end_;
|
||||
uint32_t preludeStart_;
|
||||
uint32_t toStringStart_;
|
||||
uint32_t toStringEnd_;
|
||||
// Line and column of |begin_| position, that is the position where we
|
||||
// start parsing.
|
||||
uint32_t lineno_;
|
||||
uint32_t column_;
|
||||
|
||||
LazyScript(JSFunction* fun, void* table, uint64_t packedFields,
|
||||
uint32_t begin, uint32_t end, uint32_t preludeStart,
|
||||
uint32_t begin, uint32_t end, uint32_t toStringStart,
|
||||
uint32_t lineno, uint32_t column);
|
||||
|
||||
// Create a LazyScript without initializing the closedOverBindings and the
|
||||
@ -2121,7 +2147,7 @@ class LazyScript : public gc::TenuredCell
|
||||
// with valid atoms and functions.
|
||||
static LazyScript* CreateRaw(JSContext* cx, HandleFunction fun,
|
||||
uint64_t packedData, uint32_t begin, uint32_t end,
|
||||
uint32_t preludeStart, uint32_t lineno, uint32_t column);
|
||||
uint32_t toStringStart, uint32_t lineno, uint32_t column);
|
||||
|
||||
public:
|
||||
static const uint32_t NumClosedOverBindingsLimit = 1 << NumClosedOverBindingsBits;
|
||||
@ -2133,7 +2159,7 @@ class LazyScript : public gc::TenuredCell
|
||||
const frontend::AtomVector& closedOverBindings,
|
||||
Handle<GCVector<JSFunction*, 8>> innerFunctions,
|
||||
JSVersion version, uint32_t begin, uint32_t end,
|
||||
uint32_t preludeStart, uint32_t lineno, uint32_t column);
|
||||
uint32_t toStringStart, uint32_t lineno, uint32_t column);
|
||||
|
||||
// Create a LazyScript and initialize the closedOverBindings and the
|
||||
// innerFunctions with dummy values to be replaced in a later initialization
|
||||
@ -2148,7 +2174,7 @@ class LazyScript : public gc::TenuredCell
|
||||
HandleScript script, HandleScope enclosingScope,
|
||||
HandleScriptSource sourceObject,
|
||||
uint64_t packedData, uint32_t begin, uint32_t end,
|
||||
uint32_t preludeStart, uint32_t lineno, uint32_t column);
|
||||
uint32_t toStringStart, uint32_t lineno, uint32_t column);
|
||||
|
||||
void initRuntimeFields(uint64_t packedFields);
|
||||
|
||||
@ -2329,8 +2355,11 @@ class LazyScript : public gc::TenuredCell
|
||||
uint32_t end() const {
|
||||
return end_;
|
||||
}
|
||||
uint32_t preludeStart() const {
|
||||
return preludeStart_;
|
||||
uint32_t toStringStart() const {
|
||||
return toStringStart_;
|
||||
}
|
||||
uint32_t toStringEnd() const {
|
||||
return toStringEnd_;
|
||||
}
|
||||
uint32_t lineno() const {
|
||||
return lineno_;
|
||||
@ -2339,6 +2368,12 @@ class LazyScript : public gc::TenuredCell
|
||||
return column_;
|
||||
}
|
||||
|
||||
void setToStringEnd(uint32_t toStringEnd) {
|
||||
MOZ_ASSERT(toStringStart_ <= toStringEnd);
|
||||
MOZ_ASSERT(toStringEnd_ >= end_);
|
||||
toStringEnd_ = toStringEnd;
|
||||
}
|
||||
|
||||
bool hasUncompiledEnclosingScript() const;
|
||||
|
||||
friend class GCMarker;
|
||||
|
@ -1521,18 +1521,16 @@ ParseCompileOptions(JSContext* cx, CompileOptions& options, HandleObject opts,
|
||||
}
|
||||
|
||||
static void
|
||||
my_LargeAllocFailCallback(void* data)
|
||||
my_LargeAllocFailCallback()
|
||||
{
|
||||
JSContext* cx = (JSContext*)data;
|
||||
JSRuntime* rt = cx->runtime();
|
||||
|
||||
if (cx->helperThread())
|
||||
JSContext* cx = TlsContext.get();
|
||||
if (!cx || cx->helperThread())
|
||||
return;
|
||||
|
||||
MOZ_ASSERT(!JS::CurrentThreadIsHeapBusy());
|
||||
|
||||
JS::PrepareForFullGC(cx);
|
||||
rt->gc.gc(GC_NORMAL, JS::gcreason::SHARED_MEMORY_LIMIT);
|
||||
cx->runtime()->gc.gc(GC_NORMAL, JS::gcreason::SHARED_MEMORY_LIMIT);
|
||||
}
|
||||
|
||||
static const uint32_t CacheEntry_SOURCE = 0;
|
||||
@ -2676,6 +2674,14 @@ SrcNotes(JSContext* cx, HandleScript script, Sprinter* sp)
|
||||
return false;
|
||||
break;
|
||||
|
||||
case SRC_CLASS_SPAN: {
|
||||
unsigned startOffset = GetSrcNoteOffset(sn, 0);
|
||||
unsigned endOffset = GetSrcNoteOffset(sn, 1);
|
||||
if (!sp->jsprintf(" %u %u", startOffset, endOffset))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("unrecognized srcnote");
|
||||
}
|
||||
@ -3600,8 +3606,6 @@ WorkerMain(void* arg)
|
||||
JS::SetAsyncTaskCallbacks(cx, ShellStartAsyncTaskCallback, ShellFinishAsyncTaskCallback);
|
||||
|
||||
environmentPreparer.emplace(cx);
|
||||
|
||||
JS::SetLargeAllocationFailureCallback(cx, my_LargeAllocFailCallback, (void*)cx);
|
||||
} else {
|
||||
JS_AddInterruptCallback(cx, ShellInterruptCallback);
|
||||
}
|
||||
@ -3633,8 +3637,6 @@ WorkerMain(void* arg)
|
||||
} while (0);
|
||||
|
||||
if (input->parentRuntime) {
|
||||
JS::SetLargeAllocationFailureCallback(cx, nullptr, nullptr);
|
||||
|
||||
JS::SetGetIncumbentGlobalCallback(cx, nullptr);
|
||||
JS::SetEnqueuePromiseJobCallback(cx, nullptr);
|
||||
}
|
||||
@ -8660,7 +8662,7 @@ main(int argc, char** argv, char** envp)
|
||||
|
||||
JS_SetGCParameter(cx, JSGC_MODE, JSGC_MODE_INCREMENTAL);
|
||||
|
||||
JS::SetLargeAllocationFailureCallback(cx, my_LargeAllocFailCallback, (void*)cx);
|
||||
JS::SetProcessLargeAllocationFailureCallback(my_LargeAllocFailCallback);
|
||||
|
||||
// Set some parameters to allow incremental GC in low memory conditions,
|
||||
// as is done for the browser, except in more-deterministic builds or when
|
||||
@ -8687,8 +8689,6 @@ main(int argc, char** argv, char** envp)
|
||||
printf("OOM max count: %" PRIu64 "\n", js::oom::counter);
|
||||
#endif
|
||||
|
||||
JS::SetLargeAllocationFailureCallback(cx, nullptr, nullptr);
|
||||
|
||||
JS::SetGetIncumbentGlobalCallback(cx, nullptr);
|
||||
JS::SetEnqueuePromiseJobCallback(cx, nullptr);
|
||||
JS_SetGrayGCRootsTracer(cx, nullptr, nullptr);
|
||||
|
@ -379,13 +379,6 @@ skip script test262/built-ins/TypedArrays/typedarray-arg-same-ctor-buffer-ctor-s
|
||||
skip script test262/built-ins/WeakMap/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/WeakSet/proto-from-ctor-realm.js
|
||||
|
||||
# https://bugzilla.mozilla.org/show_bug.cgi?id=1216630
|
||||
skip script test262/built-ins/Function/prototype/toString/class-declaration-complex-heritage.js
|
||||
skip script test262/built-ins/Function/prototype/toString/class-declaration-explicit-ctor.js
|
||||
skip script test262/built-ins/Function/prototype/toString/class-declaration-implicit-ctor.js
|
||||
skip script test262/built-ins/Function/prototype/toString/class-expression-explicit-ctor.js
|
||||
skip script test262/built-ins/Function/prototype/toString/class-expression-implicit-ctor.js
|
||||
|
||||
# https://bugzilla.mozilla.org/show_bug.cgi?id=1317395
|
||||
skip script test262/built-ins/ArrayBuffer/prototype/byteLength/detached-buffer.js
|
||||
|
||||
|
@ -246,11 +246,16 @@ SetPropertyOperation(JSContext* cx, JSOp op, HandleValue lval, HandleId id, Hand
|
||||
}
|
||||
|
||||
static JSFunction*
|
||||
MakeDefaultConstructor(JSContext* cx, JSOp op, JSAtom* atom, HandleObject proto)
|
||||
MakeDefaultConstructor(JSContext* cx, HandleScript script, jsbytecode* pc, HandleObject proto)
|
||||
{
|
||||
JSOp op = JSOp(*pc);
|
||||
JSAtom* atom = script->getAtom(pc);
|
||||
bool derived = op == JSOP_DERIVEDCONSTRUCTOR;
|
||||
MOZ_ASSERT(derived == !!proto);
|
||||
|
||||
jssrcnote* classNote = GetSrcNote(cx, script, pc);
|
||||
MOZ_ASSERT(classNote && SN_TYPE(classNote) == SRC_CLASS_SPAN);
|
||||
|
||||
PropertyName* lookup = derived ? cx->names().DefaultDerivedClassConstructor
|
||||
: cx->names().DefaultBaseClassConstructor;
|
||||
|
||||
@ -267,9 +272,19 @@ MakeDefaultConstructor(JSContext* cx, JSOp op, JSAtom* atom, HandleObject proto)
|
||||
|
||||
ctor->setIsConstructor();
|
||||
ctor->setIsClassConstructor();
|
||||
|
||||
MOZ_ASSERT(ctor->infallibleIsDefaultClassConstructor(cx));
|
||||
|
||||
// Create the script now, as the source span needs to be overridden for
|
||||
// toString. Calling toString on a class constructor must not return the
|
||||
// source for just the constructor function.
|
||||
JSScript *ctorScript = JSFunction::getOrCreateScript(cx, ctor);
|
||||
if (!ctorScript)
|
||||
return nullptr;
|
||||
uint32_t classStartOffset = GetSrcNoteOffset(classNote, 0);
|
||||
uint32_t classEndOffset = GetSrcNoteOffset(classNote, 1);
|
||||
ctorScript->setDefaultClassConstructorSpan(script->sourceObject(), classStartOffset,
|
||||
classEndOffset);
|
||||
|
||||
return ctor;
|
||||
}
|
||||
|
||||
@ -4216,8 +4231,7 @@ CASE(JSOP_DERIVEDCONSTRUCTOR)
|
||||
MOZ_ASSERT(REGS.sp[-1].isObject());
|
||||
ReservedRooted<JSObject*> proto(&rootObject0, ®S.sp[-1].toObject());
|
||||
|
||||
JSFunction* constructor = MakeDefaultConstructor(cx, JSOp(*REGS.pc), script->getAtom(REGS.pc),
|
||||
proto);
|
||||
JSFunction* constructor = MakeDefaultConstructor(cx, script, REGS.pc, proto);
|
||||
if (!constructor)
|
||||
goto error;
|
||||
|
||||
@ -4227,8 +4241,7 @@ END_CASE(JSOP_DERIVEDCONSTRUCTOR)
|
||||
|
||||
CASE(JSOP_CLASSCONSTRUCTOR)
|
||||
{
|
||||
JSFunction* constructor = MakeDefaultConstructor(cx, JSOp(*REGS.pc), script->getAtom(REGS.pc),
|
||||
nullptr);
|
||||
JSFunction* constructor = MakeDefaultConstructor(cx, script, REGS.pc, nullptr);
|
||||
if (!constructor)
|
||||
goto error;
|
||||
PUSH_OBJECT(*constructor);
|
||||
|
@ -63,6 +63,7 @@ using JS::DoubleNaNValue;
|
||||
|
||||
/* static */ MOZ_THREAD_LOCAL(JSContext*) js::TlsContext;
|
||||
/* static */ Atomic<size_t> JSRuntime::liveRuntimesCount;
|
||||
Atomic<JS::LargeAllocationFailureCallback> js::OnLargeAllocationFailure;
|
||||
|
||||
namespace js {
|
||||
bool gCanUseExtraThreads = true;
|
||||
@ -169,7 +170,6 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
|
||||
offthreadIonCompilationEnabled_(true),
|
||||
parallelParsingEnabled_(true),
|
||||
autoWritableJitCodeActive_(false),
|
||||
largeAllocationFailureCallback(nullptr),
|
||||
oomCallback(nullptr),
|
||||
debuggerMallocSizeOf(ReturnZeroSize),
|
||||
lastAnimationTime(0),
|
||||
@ -829,8 +829,8 @@ JSRuntime::onOutOfMemory(AllocFunction allocFunc, size_t nbytes, void* reallocPt
|
||||
void*
|
||||
JSRuntime::onOutOfMemoryCanGC(AllocFunction allocFunc, size_t bytes, void* reallocPtr)
|
||||
{
|
||||
if (largeAllocationFailureCallback && bytes >= LARGE_ALLOCATION)
|
||||
largeAllocationFailureCallback(largeAllocationFailureCallbackData);
|
||||
if (OnLargeAllocationFailure && bytes >= LARGE_ALLOCATION)
|
||||
OnLargeAllocationFailure();
|
||||
return onOutOfMemory(allocFunc, bytes, reallocPtr);
|
||||
}
|
||||
|
||||
|
@ -941,7 +941,7 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
|
||||
JS_FRIEND_API(void*) onOutOfMemory(js::AllocFunction allocator, size_t nbytes,
|
||||
void* reallocPtr = nullptr, JSContext* maybecx = nullptr);
|
||||
|
||||
/* onOutOfMemory but can call the largeAllocationFailureCallback. */
|
||||
/* onOutOfMemory but can call OnLargeAllocationFailure. */
|
||||
JS_FRIEND_API(void*) onOutOfMemoryCanGC(js::AllocFunction allocator, size_t nbytes,
|
||||
void* reallocPtr = nullptr);
|
||||
|
||||
@ -976,10 +976,6 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
|
||||
autoWritableJitCodeActive_ = b;
|
||||
}
|
||||
|
||||
/* See comment for JS::SetLargeAllocationFailureCallback in jsapi.h. */
|
||||
js::ActiveThreadData<JS::LargeAllocationFailureCallback> largeAllocationFailureCallback;
|
||||
js::ActiveThreadData<void*> largeAllocationFailureCallbackData;
|
||||
|
||||
/* See comment for JS::SetOutOfMemoryCallback in jsapi.h. */
|
||||
js::ActiveThreadData<JS::OutOfMemoryCallback> oomCallback;
|
||||
js::ActiveThreadData<void*> oomCallbackData;
|
||||
@ -1341,6 +1337,10 @@ ZoneGroup::callAfterMinorGC(void (*thunk)(void* data), void* data)
|
||||
nursery().queueSweepAction(thunk, data);
|
||||
}
|
||||
|
||||
// This callback is set by JS::SetProcessLargeAllocationFailureCallback
|
||||
// and may be null. See comment in jsapi.h.
|
||||
extern mozilla::Atomic<JS::LargeAllocationFailureCallback> OnLargeAllocationFailure;
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
@ -123,9 +123,8 @@ SharedArrayRawBuffer::New(JSContext* cx, uint32_t length)
|
||||
// Test >= to guard against the case where multiple extant runtimes
|
||||
// race to allocate.
|
||||
if (++numLive >= maxLive) {
|
||||
JSRuntime* rt = cx->runtime();
|
||||
if (rt->largeAllocationFailureCallback)
|
||||
rt->largeAllocationFailureCallback(rt->largeAllocationFailureCallbackData);
|
||||
if (OnLargeAllocationFailure)
|
||||
OnLargeAllocationFailure();
|
||||
if (numLive >= maxLive) {
|
||||
numLive--;
|
||||
return nullptr;
|
||||
|
@ -325,7 +325,7 @@ struct js::AsmJSMetadata : Metadata, AsmJSMetadataCacheablePod
|
||||
// Function constructor, this will be the first character in the function
|
||||
// source. Otherwise, it will be the opening parenthesis of the arguments
|
||||
// list.
|
||||
uint32_t preludeStart;
|
||||
uint32_t toStringStart;
|
||||
uint32_t srcStart;
|
||||
uint32_t srcBodyStart;
|
||||
bool strict;
|
||||
@ -1779,7 +1779,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||
if (!asmJSMetadata_)
|
||||
return false;
|
||||
|
||||
asmJSMetadata_->preludeStart = moduleFunctionNode_->pn_funbox->preludeStart;
|
||||
asmJSMetadata_->toStringStart = moduleFunctionNode_->pn_funbox->toStringStart;
|
||||
asmJSMetadata_->srcStart = moduleFunctionNode_->pn_body->pn_pos.begin;
|
||||
asmJSMetadata_->srcBodyStart = parser_.tokenStream.currentToken().pos.end;
|
||||
asmJSMetadata_->strict = parser_.pc->sc()->strict() &&
|
||||
@ -7074,7 +7074,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line)
|
||||
TokenStream& tokenStream = m.tokenStream();
|
||||
|
||||
tokenStream.consumeKnownToken(TOK_FUNCTION, TokenStream::Operand);
|
||||
uint32_t preludeStart = tokenStream.currentToken().pos.begin;
|
||||
uint32_t toStringStart = tokenStream.currentToken().pos.begin;
|
||||
*line = tokenStream.srcCoords.lineNum(tokenStream.currentToken().pos.end);
|
||||
|
||||
TokenKind tk;
|
||||
@ -7097,8 +7097,9 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line)
|
||||
|
||||
ParseContext* outerpc = m.parser().pc;
|
||||
Directives directives(outerpc);
|
||||
FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, preludeStart, directives, NotGenerator,
|
||||
SyncFunction, /* tryAnnexB = */ false);
|
||||
FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, toStringStart, directives,
|
||||
NotGenerator, SyncFunction,
|
||||
/* tryAnnexB = */ false);
|
||||
if (!funbox)
|
||||
return false;
|
||||
funbox->initWithEnclosingParseContext(outerpc, frontend::Statement);
|
||||
@ -8094,7 +8095,7 @@ HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& me
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t begin = metadata.preludeStart;
|
||||
uint32_t begin = metadata.toStringStart;
|
||||
uint32_t end = metadata.srcEndAfterCurly();
|
||||
Rooted<JSFlatString*> src(cx, source->substringDontDeflate(cx, begin, end));
|
||||
if (!src)
|
||||
@ -8576,7 +8577,7 @@ LookupAsmJSModuleInCache(JSContext* cx, AsmJSParser& parser, bool* loadedFromCac
|
||||
return true;
|
||||
|
||||
// See AsmJSMetadata comment as well as ModuleValidator::init().
|
||||
asmJSMetadata->preludeStart = parser.pc->functionBox()->preludeStart;
|
||||
asmJSMetadata->toStringStart = parser.pc->functionBox()->toStringStart;
|
||||
asmJSMetadata->srcStart = parser.pc->functionBox()->functionNode->pn_body->pn_pos.begin;
|
||||
asmJSMetadata->srcBodyStart = parser.tokenStream.currentToken().pos.end;
|
||||
asmJSMetadata->strict = parser.pc->sc()->strict() && !parser.pc->sc()->hasExplicitUseStrict();
|
||||
@ -8877,7 +8878,7 @@ js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda
|
||||
MOZ_ASSERT(IsAsmJSModule(fun));
|
||||
|
||||
const AsmJSMetadata& metadata = AsmJSModuleFunctionToModule(fun).metadata().asAsmJS();
|
||||
uint32_t begin = metadata.preludeStart;
|
||||
uint32_t begin = metadata.toStringStart;
|
||||
uint32_t end = metadata.srcEndAfterCurly();
|
||||
ScriptSource* source = metadata.scriptSource.get();
|
||||
|
||||
|
@ -77,9 +77,8 @@ AllocateCodeSegment(JSContext* cx, uint32_t codeLength)
|
||||
// to purge all memory (which, in gecko, does a purging GC/CC/GC), do that
|
||||
// then retry the allocation.
|
||||
if (!p) {
|
||||
JSRuntime* rt = cx->runtime();
|
||||
if (rt->largeAllocationFailureCallback) {
|
||||
rt->largeAllocationFailureCallback(rt->largeAllocationFailureCallbackData);
|
||||
if (OnLargeAllocationFailure) {
|
||||
OnLargeAllocationFailure();
|
||||
p = AllocateExecutableMemory(codeLength, ProtectionSetting::Writable);
|
||||
}
|
||||
}
|
||||
|
@ -1447,12 +1447,85 @@ XPCJSContext::CustomOutOfMemoryCallback()
|
||||
}
|
||||
|
||||
void
|
||||
XPCJSContext::CustomLargeAllocationFailureCallback()
|
||||
XPCJSContext::OnLargeAllocationFailure()
|
||||
{
|
||||
CycleCollectedJSContext::SetLargeAllocationFailure(OOMState::Reporting);
|
||||
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
if (os) {
|
||||
os->NotifyObservers(nullptr, "memory-pressure", u"heap-minimize");
|
||||
}
|
||||
|
||||
CycleCollectedJSContext::SetLargeAllocationFailure(OOMState::Reported);
|
||||
}
|
||||
|
||||
class LargeAllocationFailureRunnable final : public Runnable
|
||||
{
|
||||
Mutex mMutex;
|
||||
CondVar mCondVar;
|
||||
bool mWaiting;
|
||||
|
||||
virtual ~LargeAllocationFailureRunnable()
|
||||
{
|
||||
MOZ_ASSERT(!mWaiting);
|
||||
}
|
||||
|
||||
protected:
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
XPCJSContext::Get()->OnLargeAllocationFailure();
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
MOZ_ASSERT(mWaiting);
|
||||
|
||||
mWaiting = false;
|
||||
mCondVar.Notify();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
public:
|
||||
LargeAllocationFailureRunnable()
|
||||
: mMutex("LargeAllocationFailureRunnable::mMutex"),
|
||||
mCondVar(mMutex, "LargeAllocationFailureRunnable::mCondVar"),
|
||||
mWaiting(true)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
}
|
||||
|
||||
void BlockUntilDone()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
while (mWaiting) {
|
||||
mCondVar.Wait();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
OnLargeAllocationFailureCallback()
|
||||
{
|
||||
// This callback can be called from any thread, including internal JS helper
|
||||
// and DOM worker threads. We need to send the low-memory event via the
|
||||
// observer service which can only be called on the main thread, so proxy to
|
||||
// the main thread if we're not there already. The purpose of this callback
|
||||
// is to synchronously free some memory so the caller can retry a failed
|
||||
// allocation, so block on the completion.
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
XPCJSContext::Get()->OnLargeAllocationFailure();
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<LargeAllocationFailureRunnable> r = new LargeAllocationFailureRunnable;
|
||||
if (NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(r)))) {
|
||||
return;
|
||||
}
|
||||
|
||||
r->BlockUntilDone();
|
||||
}
|
||||
|
||||
size_t
|
||||
@ -3541,6 +3614,7 @@ XPCJSContext::Initialize()
|
||||
js::SetActivityCallback(cx, ActivityCallback, this);
|
||||
JS_AddInterruptCallback(cx, InterruptCallback);
|
||||
js::SetWindowProxyClass(cx, &OuterWindowProxyClass);
|
||||
JS::SetProcessLargeAllocationFailureCallback(OnLargeAllocationFailureCallback);
|
||||
|
||||
// The JS engine needs to keep the source code around in order to implement
|
||||
// Function.prototype.toSource(). It'd be nice to not have to do this for
|
||||
|
@ -529,7 +529,7 @@ public:
|
||||
|
||||
void CustomGCCallback(JSGCStatus status) override;
|
||||
void CustomOutOfMemoryCallback() override;
|
||||
void CustomLargeAllocationFailureCallback() override;
|
||||
void OnLargeAllocationFailure();
|
||||
static void GCSliceCallback(JSContext* cx,
|
||||
JS::GCProgress progress,
|
||||
const JS::GCDescription& desc);
|
||||
|
@ -7144,7 +7144,7 @@ nsLayoutUtils::GetDeviceContextForScreenInfo(nsPIDOMWindowOuter* aWindow)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
win->EnsureSizeUpToDate();
|
||||
win->EnsureSizeAndPositionUpToDate();
|
||||
|
||||
RefPtr<nsPresContext> presContext;
|
||||
docShell->GetPresContext(getter_AddRefs(presContext));
|
||||
|
@ -49,6 +49,7 @@
|
||||
#include "mozilla/net/NeckoChild.h"
|
||||
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
@ -2203,17 +2204,24 @@ Predictor::Resetter::Complete()
|
||||
|
||||
// Helper functions to make using the predictor easier from native code
|
||||
|
||||
static StaticRefPtr<nsINetworkPredictor> sPredictor;
|
||||
|
||||
static nsresult
|
||||
EnsureGlobalPredictor(nsINetworkPredictor **aPredictor)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINetworkPredictor> predictor =
|
||||
do_GetService("@mozilla.org/network/predictor;1",
|
||||
&rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!sPredictor) {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINetworkPredictor> predictor =
|
||||
do_GetService("@mozilla.org/network/predictor;1",
|
||||
&rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
sPredictor = predictor;
|
||||
ClearOnShutdown(&sPredictor);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsINetworkPredictor> predictor = sPredictor.get();
|
||||
predictor.forget(aPredictor);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -619,7 +619,7 @@ this.ExtensionContent = {
|
||||
getContext(extension, window) {
|
||||
let extensions = DocumentManager.getContexts(window);
|
||||
|
||||
let context = extensions.get(this);
|
||||
let context = extensions.get(extension);
|
||||
if (!context) {
|
||||
context = new ContentScriptContextChild(extension, window);
|
||||
extensions.set(extension, context);
|
||||
|
@ -176,83 +176,6 @@ var Service = {
|
||||
},
|
||||
};
|
||||
|
||||
// API Levels Helpers
|
||||
|
||||
// Find the add-on associated with this document via the
|
||||
// principal's addonId attribute. This value is computed by
|
||||
// extensionURIToAddonID, which ensures that we don't inject our
|
||||
// API into webAccessibleResources or remote web pages.
|
||||
function getAddonIdForWindow(window) {
|
||||
return Cu.getObjectPrincipal(window).addonId;
|
||||
}
|
||||
|
||||
const API_LEVELS = Object.freeze({
|
||||
NO_PRIVILEGES: 0,
|
||||
CONTENTSCRIPT_PRIVILEGES: 1,
|
||||
FULL_PRIVILEGES: 2,
|
||||
});
|
||||
|
||||
// Finds the API Level ("FULL_PRIVILEGES", "CONTENTSCRIPT_PRIVILEGES", "NO_PRIVILEGES")
|
||||
// with a given a window object.
|
||||
function getAPILevelForWindow(window, addonId) {
|
||||
const {NO_PRIVILEGES, CONTENTSCRIPT_PRIVILEGES, FULL_PRIVILEGES} = API_LEVELS;
|
||||
|
||||
// Non WebExtension URLs and WebExtension URLs from a different extension
|
||||
// has no access to APIs.
|
||||
if (!addonId || getAddonIdForWindow(window) != addonId) {
|
||||
return NO_PRIVILEGES;
|
||||
}
|
||||
|
||||
if (!ExtensionManagement.isExtensionProcess) {
|
||||
return CONTENTSCRIPT_PRIVILEGES;
|
||||
}
|
||||
|
||||
let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDocShell);
|
||||
|
||||
// Handling of ExtensionPages running inside sub-frames.
|
||||
if (docShell.sameTypeParent) {
|
||||
let parentWindow = docShell.sameTypeParent.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindow);
|
||||
|
||||
// The option page iframe embedded in the about:addons tab should have
|
||||
// full API level privileges. (see Bug 1256282 for rationale)
|
||||
let parentDocument = parentWindow.document;
|
||||
let parentIsSystemPrincipal = Services.scriptSecurityManager
|
||||
.isSystemPrincipal(parentDocument.nodePrincipal);
|
||||
|
||||
if (parentDocument.location.href == "about:addons" && parentIsSystemPrincipal) {
|
||||
return FULL_PRIVILEGES;
|
||||
}
|
||||
|
||||
// NOTE: Special handling for devtools panels using a chrome iframe here
|
||||
// for the devtools panel, it is needed because a content iframe breaks
|
||||
// switching between docked and undocked mode (see bug 1075490).
|
||||
let devtoolsBrowser = parentDocument.querySelector(
|
||||
"browser[webextension-view-type='devtools_panel']");
|
||||
if (devtoolsBrowser && devtoolsBrowser.contentWindow === window &&
|
||||
parentIsSystemPrincipal) {
|
||||
return FULL_PRIVILEGES;
|
||||
}
|
||||
|
||||
// The addon iframes embedded in a addon page from with the same addonId
|
||||
// should have the same privileges of the sameTypeParent.
|
||||
// (see Bug 1258347 for rationale)
|
||||
let parentSameAddonPrivileges = getAPILevelForWindow(parentWindow, addonId);
|
||||
if (parentSameAddonPrivileges > NO_PRIVILEGES) {
|
||||
return parentSameAddonPrivileges;
|
||||
}
|
||||
|
||||
// In all the other cases, WebExtension URLs loaded into sub-frame UI
|
||||
// will have "content script API level privileges".
|
||||
// (see Bug 1214658 for rationale)
|
||||
return CONTENTSCRIPT_PRIVILEGES;
|
||||
}
|
||||
|
||||
// WebExtension URLs loaded into top frames UI could have full API level privileges.
|
||||
return FULL_PRIVILEGES;
|
||||
}
|
||||
|
||||
let cacheInvalidated = 0;
|
||||
function onCacheInvalidate() {
|
||||
cacheInvalidated++;
|
||||
@ -279,11 +202,6 @@ ExtensionManagement = {
|
||||
|
||||
getURLForExtension,
|
||||
|
||||
// exported API Level Helpers
|
||||
getAddonIdForWindow,
|
||||
getAPILevelForWindow,
|
||||
API_LEVELS,
|
||||
|
||||
APIs,
|
||||
};
|
||||
|
||||
|
@ -168,10 +168,8 @@ class ScriptMatcher {
|
||||
}
|
||||
}
|
||||
|
||||
function getMessageManager(contentWindow) {
|
||||
let docShell = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDocShell)
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor);
|
||||
function getMessageManager(window) {
|
||||
let docShell = window.document.docShell.QueryInterface(Ci.nsIInterfaceRequestor);
|
||||
try {
|
||||
return docShell.getInterface(Ci.nsIContentFrameMessageManager);
|
||||
} catch (e) {
|
||||
@ -448,26 +446,67 @@ DocumentManager = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks that all parent frames for the given withdow either have the
|
||||
* same add-on ID, or are special chrome-privileged documents such as
|
||||
* about:addons or developer tools panels.
|
||||
*
|
||||
* @param {Window} window
|
||||
* The window to check.
|
||||
* @param {string} addonId
|
||||
* The add-on ID to check.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
checkParentFrames(window, addonId) {
|
||||
while (window.parent !== window) {
|
||||
let {frameElement} = window;
|
||||
window = window.parent;
|
||||
|
||||
let principal = window.document.nodePrincipal;
|
||||
|
||||
if (Services.scriptSecurityManager.isSystemPrincipal(principal)) {
|
||||
// The add-on manager is a special case, since it contains extension
|
||||
// options pages in same-type <browser> frames.
|
||||
if (window.location.href === "about:addons") {
|
||||
return true;
|
||||
}
|
||||
|
||||
// NOTE: Special handling for devtools panels using a chrome iframe here
|
||||
// for the devtools panel, it is needed because a content iframe breaks
|
||||
// switching between docked and undocked mode (see bug 1075490).
|
||||
if (frameElement &&
|
||||
frameElement.mozMatchesSelector("browser[webextension-view-type='devtools_panel']")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (principal.addonId !== addonId) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
loadInto(window) {
|
||||
let extensionId = ExtensionManagement.getAddonIdForWindow(window);
|
||||
if (!extensionId) {
|
||||
let {addonId} = Cu.getObjectPrincipal(window);
|
||||
if (!addonId) {
|
||||
return;
|
||||
}
|
||||
|
||||
let extension = ExtensionManager.get(extensionId);
|
||||
let extension = ExtensionManager.get(addonId);
|
||||
if (!extension) {
|
||||
throw new Error(`No registered extension for ID ${extensionId}`);
|
||||
throw new Error(`No registered extension for ID ${addonId}`);
|
||||
}
|
||||
|
||||
let apiLevel = ExtensionManagement.getAPILevelForWindow(window, extensionId);
|
||||
const levels = ExtensionManagement.API_LEVELS;
|
||||
|
||||
if (apiLevel === levels.CONTENTSCRIPT_PRIVILEGES) {
|
||||
ExtensionContent.initExtensionContext(extension.realExtension, window);
|
||||
} else if (apiLevel === levels.FULL_PRIVILEGES) {
|
||||
if (this.checkParentFrames(window, addonId) && ExtensionManagement.isExtensionProcess) {
|
||||
// We're in a top-level extension frame, or a sub-frame thereof,
|
||||
// in the extension process. Inject the full extension page API.
|
||||
ExtensionPageChild.initExtensionContext(extension.realExtension, window);
|
||||
} else {
|
||||
throw new Error(`Unexpected window with extension ID ${extensionId}`);
|
||||
// We're in a content sub-frame or not in the extension process.
|
||||
// Only inject a minimal content script API.
|
||||
ExtensionContent.initExtensionContext(extension.realExtension, window);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -1,70 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
const {Service} = Cu.import("resource://gre/modules/ExtensionManagement.jsm", {});
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "uuidGen",
|
||||
"@mozilla.org/uuid-generator;1",
|
||||
"nsIUUIDGenerator");
|
||||
|
||||
function createWindowWithAddonId(addonId) {
|
||||
const uuid = uuidGen.generateUUID().number.slice(1, -1);
|
||||
|
||||
const url = `moz-extension://${uuid}/`;
|
||||
|
||||
// Set the add-on ID for this moz-extensions: URL.
|
||||
Service.uuidMap.set(uuid, {id: addonId});
|
||||
do_register_cleanup(() => {
|
||||
Service.uuidMap.delete(uuid);
|
||||
});
|
||||
|
||||
let baseURI = Services.io.newURI(url);
|
||||
let principal = Services.scriptSecurityManager
|
||||
.createCodebasePrincipal(baseURI, {});
|
||||
let chromeNav = Services.appShell.createWindowlessBrowser(true);
|
||||
let interfaceRequestor = chromeNav.QueryInterface(Ci.nsIInterfaceRequestor);
|
||||
let docShell = interfaceRequestor.getInterface(Ci.nsIDocShell);
|
||||
docShell.createAboutBlankContentViewer(principal);
|
||||
|
||||
return {chromeNav, window: docShell.contentViewer.DOMDocument.defaultView};
|
||||
}
|
||||
|
||||
add_task(function* test_eventpages() {
|
||||
Service.init();
|
||||
|
||||
const {getAPILevelForWindow, getAddonIdForWindow} = ExtensionManagement;
|
||||
const {NO_PRIVILEGES, FULL_PRIVILEGES} = ExtensionManagement.API_LEVELS;
|
||||
const FAKE_ADDON_ID = "fakeAddonId";
|
||||
const OTHER_ADDON_ID = "otherFakeAddonId";
|
||||
const EMPTY_ADDON_ID = "";
|
||||
|
||||
let fakeAddonId = createWindowWithAddonId(FAKE_ADDON_ID);
|
||||
equal(getAddonIdForWindow(fakeAddonId.window), FAKE_ADDON_ID,
|
||||
"the window has the expected addonId");
|
||||
|
||||
let apiLevel = getAPILevelForWindow(fakeAddonId.window, FAKE_ADDON_ID);
|
||||
equal(apiLevel, FULL_PRIVILEGES,
|
||||
"apiLevel for the window with the right addonId should be FULL_PRIVILEGES");
|
||||
|
||||
apiLevel = getAPILevelForWindow(fakeAddonId.window, OTHER_ADDON_ID);
|
||||
equal(apiLevel, NO_PRIVILEGES,
|
||||
"apiLevel for the window with a different addonId should be NO_PRIVILEGES");
|
||||
|
||||
fakeAddonId.chromeNav.close();
|
||||
|
||||
// NOTE: check that window with an empty addon Id (which are window that are
|
||||
// not Extensions pages) always get no WebExtensions APIs.
|
||||
let emptyAddonId = createWindowWithAddonId(EMPTY_ADDON_ID);
|
||||
equal(getAddonIdForWindow(emptyAddonId.window), EMPTY_ADDON_ID,
|
||||
"the window has the expected addonId");
|
||||
|
||||
apiLevel = getAPILevelForWindow(emptyAddonId.window, EMPTY_ADDON_ID);
|
||||
equal(apiLevel, NO_PRIVILEGES,
|
||||
"apiLevel for empty addonId should be NO_PRIVILEGES");
|
||||
|
||||
apiLevel = getAPILevelForWindow(emptyAddonId.window, OTHER_ADDON_ID);
|
||||
equal(apiLevel, NO_PRIVILEGES,
|
||||
"apiLevel for an 'empty addonId' window should be always NO_PRIVILEGES");
|
||||
|
||||
emptyAddonId.chromeNav.close();
|
||||
});
|
@ -80,7 +80,6 @@ skip-if = os == "android"
|
||||
[test_ext_themes_supported_properties.js]
|
||||
[test_ext_topSites.js]
|
||||
skip-if = os == "android"
|
||||
[test_getAPILevelForWindow.js]
|
||||
[test_ext_legacy_extension_context.js]
|
||||
[test_ext_legacy_extension_embedding.js]
|
||||
[test_locale_converter.js]
|
||||
|
@ -2674,7 +2674,8 @@ profiler_is_active()
|
||||
void
|
||||
profiler_set_frame_number(int aFrameNumber)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
// This function runs both on (via tests) and off the main thread.
|
||||
|
||||
MOZ_RELEASE_ASSERT(gPS);
|
||||
|
||||
PS::AutoLock lock(gPSMutex);
|
||||
|
@ -592,8 +592,6 @@ CycleCollectedJSContext::Initialize(JSRuntime* aParentRuntime,
|
||||
|
||||
JS_SetObjectsTenuredCallback(mJSContext, JSObjectsTenuredCb, this);
|
||||
JS::SetOutOfMemoryCallback(mJSContext, OutOfMemoryCallback, this);
|
||||
JS::SetLargeAllocationFailureCallback(mJSContext,
|
||||
LargeAllocationFailureCallback, this);
|
||||
JS_SetExternalStringSizeofCallback(mJSContext, SizeofExternalStringCallback);
|
||||
JS::SetBuildIdOp(mJSContext, GetBuildId);
|
||||
JS::SetWarningReporter(mJSContext, MozCrashWarningReporter);
|
||||
@ -971,14 +969,6 @@ CycleCollectedJSContext::OutOfMemoryCallback(JSContext* aContext,
|
||||
self->OnOutOfMemory();
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
CycleCollectedJSContext::LargeAllocationFailureCallback(void* aData)
|
||||
{
|
||||
CycleCollectedJSContext* self = static_cast<CycleCollectedJSContext*>(aData);
|
||||
|
||||
self->OnLargeAllocationFailure();
|
||||
}
|
||||
|
||||
/* static */ size_t
|
||||
CycleCollectedJSContext::SizeofExternalStringCallback(JSString* aStr,
|
||||
MallocSizeOf aMallocSizeOf)
|
||||
@ -1755,13 +1745,11 @@ CycleCollectedJSContext::OnOutOfMemory()
|
||||
}
|
||||
|
||||
void
|
||||
CycleCollectedJSContext::OnLargeAllocationFailure()
|
||||
CycleCollectedJSContext::SetLargeAllocationFailure(OOMState aNewState)
|
||||
{
|
||||
MOZ_ASSERT(mJSContext);
|
||||
|
||||
AnnotateAndSetOutOfMemory(&mLargeAllocationFailureState, OOMState::Reporting);
|
||||
CustomLargeAllocationFailureCallback();
|
||||
AnnotateAndSetOutOfMemory(&mLargeAllocationFailureState, OOMState::Reported);
|
||||
AnnotateAndSetOutOfMemory(&mLargeAllocationFailureState, aNewState);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -160,7 +160,6 @@ protected:
|
||||
|
||||
virtual void CustomGCCallback(JSGCStatus aStatus) {}
|
||||
virtual void CustomOutOfMemoryCallback() {}
|
||||
virtual void CustomLargeAllocationFailureCallback() {}
|
||||
|
||||
std::queue<nsCOMPtr<nsIRunnable>> mPromiseMicroTaskQueue;
|
||||
std::queue<nsCOMPtr<nsIRunnable>> mDebuggerPromiseMicroTaskQueue;
|
||||
@ -218,7 +217,6 @@ private:
|
||||
JS::GCNurseryProgress aProgress,
|
||||
JS::gcreason::Reason aReason);
|
||||
static void OutOfMemoryCallback(JSContext* aContext, void* aData);
|
||||
static void LargeAllocationFailureCallback(void* aData);
|
||||
/**
|
||||
* Callback for reporting external string memory.
|
||||
*/
|
||||
@ -287,11 +285,12 @@ public:
|
||||
Recovered
|
||||
};
|
||||
|
||||
void SetLargeAllocationFailure(OOMState aNewState);
|
||||
|
||||
private:
|
||||
void AnnotateAndSetOutOfMemory(OOMState* aStatePtr, OOMState aNewState);
|
||||
void OnGC(JSGCStatus aStatus);
|
||||
void OnOutOfMemory();
|
||||
void OnLargeAllocationFailure();
|
||||
|
||||
public:
|
||||
void AddJSHolder(void* aHolder, nsScriptObjectTracer* aTracer);
|
||||
|
@ -325,7 +325,8 @@ struct nsThreadShutdownContext
|
||||
|
||||
// NB: This will be the last reference.
|
||||
NotNull<RefPtr<nsThread>> mTerminatingThread;
|
||||
NotNull<nsThread*> mJoiningThread;
|
||||
NotNull<nsThread*> MOZ_UNSAFE_REF("Thread manager is holding reference to joining thread")
|
||||
mJoiningThread;
|
||||
bool mAwaitingShutdownAck;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user