forked from mirrors/gecko-dev
Merge mozilla-central to inbound. a=merge CLOSED TREE
This commit is contained in:
commit
338aeb2777
95 changed files with 1790 additions and 1057 deletions
|
|
@ -307,7 +307,8 @@ void AccessibleWrap::GetRoleDescription(role aRole,
|
|||
return;
|
||||
}
|
||||
|
||||
if (aRole == roles::HEADING) {
|
||||
if (aRole == roles::HEADING && aAttributes) {
|
||||
// The heading level is an attribute, so we need that.
|
||||
nsString level;
|
||||
rv = aAttributes->GetStringProperty(NS_LITERAL_CSTRING("level"), level);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
|
|
@ -411,7 +412,7 @@ bool AccessibleWrap::WrapperRangeInfo(double* aCurVal, double* aMinVal,
|
|||
return false;
|
||||
}
|
||||
|
||||
mozilla::java::GeckoBundle::LocalRef AccessibleWrap::ToBundle() {
|
||||
mozilla::java::GeckoBundle::LocalRef AccessibleWrap::ToBundle(bool aSmall) {
|
||||
nsAutoString name;
|
||||
Name(name);
|
||||
nsAutoString textValue;
|
||||
|
|
@ -419,6 +420,10 @@ mozilla::java::GeckoBundle::LocalRef AccessibleWrap::ToBundle() {
|
|||
nsAutoString nodeID;
|
||||
WrapperDOMNodeID(nodeID);
|
||||
|
||||
if (aSmall) {
|
||||
return ToBundle(State(), Bounds(), ActionCount(), name, textValue, nodeID);
|
||||
}
|
||||
|
||||
double curValue = UnspecifiedNaN<double>();
|
||||
double minValue = UnspecifiedNaN<double>();
|
||||
double maxValue = UnspecifiedNaN<double>();
|
||||
|
|
@ -513,63 +518,66 @@ mozilla::java::GeckoBundle::LocalRef AccessibleWrap::ToBundle(
|
|||
GECKOBUNDLE_PUT(nodeInfo, "rangeInfo", rangeInfo);
|
||||
}
|
||||
|
||||
nsString inputTypeAttr;
|
||||
nsAccUtils::GetAccAttr(aAttributes, nsGkAtoms::textInputType, inputTypeAttr);
|
||||
int32_t inputType = GetInputType(inputTypeAttr);
|
||||
if (inputType) {
|
||||
GECKOBUNDLE_PUT(nodeInfo, "inputType",
|
||||
java::sdk::Integer::ValueOf(inputType));
|
||||
}
|
||||
|
||||
nsString posinset;
|
||||
nsresult rv =
|
||||
aAttributes->GetStringProperty(NS_LITERAL_CSTRING("posinset"), posinset);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
int32_t rowIndex;
|
||||
if (sscanf(NS_ConvertUTF16toUTF8(posinset).get(), "%d", &rowIndex) > 0) {
|
||||
GECKOBUNDLE_START(collectionItemInfo);
|
||||
GECKOBUNDLE_PUT(collectionItemInfo, "rowIndex",
|
||||
java::sdk::Integer::ValueOf(rowIndex));
|
||||
GECKOBUNDLE_PUT(collectionItemInfo, "columnIndex",
|
||||
java::sdk::Integer::ValueOf(0));
|
||||
GECKOBUNDLE_PUT(collectionItemInfo, "rowSpan",
|
||||
java::sdk::Integer::ValueOf(1));
|
||||
GECKOBUNDLE_PUT(collectionItemInfo, "columnSpan",
|
||||
java::sdk::Integer::ValueOf(1));
|
||||
GECKOBUNDLE_FINISH(collectionItemInfo);
|
||||
|
||||
GECKOBUNDLE_PUT(nodeInfo, "collectionItemInfo", collectionItemInfo);
|
||||
if (aAttributes) {
|
||||
nsString inputTypeAttr;
|
||||
nsAccUtils::GetAccAttr(aAttributes, nsGkAtoms::textInputType,
|
||||
inputTypeAttr);
|
||||
int32_t inputType = GetInputType(inputTypeAttr);
|
||||
if (inputType) {
|
||||
GECKOBUNDLE_PUT(nodeInfo, "inputType",
|
||||
java::sdk::Integer::ValueOf(inputType));
|
||||
}
|
||||
}
|
||||
|
||||
nsString colSize;
|
||||
rv = aAttributes->GetStringProperty(NS_LITERAL_CSTRING("child-item-count"),
|
||||
colSize);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
int32_t rowCount;
|
||||
if (sscanf(NS_ConvertUTF16toUTF8(colSize).get(), "%d", &rowCount) > 0) {
|
||||
GECKOBUNDLE_START(collectionInfo);
|
||||
GECKOBUNDLE_PUT(collectionInfo, "rowCount",
|
||||
java::sdk::Integer::ValueOf(rowCount));
|
||||
GECKOBUNDLE_PUT(collectionInfo, "columnCount",
|
||||
java::sdk::Integer::ValueOf(1));
|
||||
nsString posinset;
|
||||
nsresult rv = aAttributes->GetStringProperty(NS_LITERAL_CSTRING("posinset"),
|
||||
posinset);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
int32_t rowIndex;
|
||||
if (sscanf(NS_ConvertUTF16toUTF8(posinset).get(), "%d", &rowIndex) > 0) {
|
||||
GECKOBUNDLE_START(collectionItemInfo);
|
||||
GECKOBUNDLE_PUT(collectionItemInfo, "rowIndex",
|
||||
java::sdk::Integer::ValueOf(rowIndex));
|
||||
GECKOBUNDLE_PUT(collectionItemInfo, "columnIndex",
|
||||
java::sdk::Integer::ValueOf(0));
|
||||
GECKOBUNDLE_PUT(collectionItemInfo, "rowSpan",
|
||||
java::sdk::Integer::ValueOf(1));
|
||||
GECKOBUNDLE_PUT(collectionItemInfo, "columnSpan",
|
||||
java::sdk::Integer::ValueOf(1));
|
||||
GECKOBUNDLE_FINISH(collectionItemInfo);
|
||||
|
||||
nsString unused;
|
||||
rv = aAttributes->GetStringProperty(NS_LITERAL_CSTRING("hierarchical"),
|
||||
unused);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
GECKOBUNDLE_PUT(collectionInfo, "isHierarchical",
|
||||
java::sdk::Boolean::TRUE());
|
||||
GECKOBUNDLE_PUT(nodeInfo, "collectionItemInfo", collectionItemInfo);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsSelect()) {
|
||||
int32_t selectionMode = (aState & states::MULTISELECTABLE) ? 2 : 1;
|
||||
GECKOBUNDLE_PUT(collectionInfo, "selectionMode",
|
||||
java::sdk::Integer::ValueOf(selectionMode));
|
||||
nsString colSize;
|
||||
rv = aAttributes->GetStringProperty(NS_LITERAL_CSTRING("child-item-count"),
|
||||
colSize);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
int32_t rowCount;
|
||||
if (sscanf(NS_ConvertUTF16toUTF8(colSize).get(), "%d", &rowCount) > 0) {
|
||||
GECKOBUNDLE_START(collectionInfo);
|
||||
GECKOBUNDLE_PUT(collectionInfo, "rowCount",
|
||||
java::sdk::Integer::ValueOf(rowCount));
|
||||
GECKOBUNDLE_PUT(collectionInfo, "columnCount",
|
||||
java::sdk::Integer::ValueOf(1));
|
||||
|
||||
nsString unused;
|
||||
rv = aAttributes->GetStringProperty(NS_LITERAL_CSTRING("hierarchical"),
|
||||
unused);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
GECKOBUNDLE_PUT(collectionInfo, "isHierarchical",
|
||||
java::sdk::Boolean::TRUE());
|
||||
}
|
||||
|
||||
if (IsSelect()) {
|
||||
int32_t selectionMode = (aState & states::MULTISELECTABLE) ? 2 : 1;
|
||||
GECKOBUNDLE_PUT(collectionInfo, "selectionMode",
|
||||
java::sdk::Integer::ValueOf(selectionMode));
|
||||
}
|
||||
|
||||
GECKOBUNDLE_FINISH(collectionInfo);
|
||||
GECKOBUNDLE_PUT(nodeInfo, "collectionInfo", collectionInfo);
|
||||
}
|
||||
GECKOBUNDLE_FINISH(collectionInfo);
|
||||
|
||||
GECKOBUNDLE_PUT(nodeInfo, "collectionInfo", collectionInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -586,42 +594,3 @@ mozilla::java::GeckoBundle::LocalRef AccessibleWrap::ToBundle(
|
|||
|
||||
return nodeInfo;
|
||||
}
|
||||
|
||||
mozilla::java::GeckoBundle::LocalRef AccessibleWrap::ToSmallBundle() {
|
||||
return ToSmallBundle(State(), Bounds(), ActionCount());
|
||||
}
|
||||
|
||||
mozilla::java::GeckoBundle::LocalRef AccessibleWrap::ToSmallBundle(
|
||||
const uint64_t aState, const nsIntRect& aBounds,
|
||||
const uint8_t aActionCount) {
|
||||
GECKOBUNDLE_START(nodeInfo);
|
||||
GECKOBUNDLE_PUT(nodeInfo, "id", java::sdk::Integer::ValueOf(VirtualViewID()));
|
||||
|
||||
AccessibleWrap* parent = WrapperParent();
|
||||
GECKOBUNDLE_PUT(
|
||||
nodeInfo, "parentId",
|
||||
java::sdk::Integer::ValueOf(parent ? parent->VirtualViewID() : 0));
|
||||
|
||||
uint32_t flags = GetFlags(WrapperRole(), aState, aActionCount);
|
||||
GECKOBUNDLE_PUT(nodeInfo, "flags", java::sdk::Integer::ValueOf(flags));
|
||||
GECKOBUNDLE_PUT(nodeInfo, "className",
|
||||
java::sdk::Integer::ValueOf(AndroidClass()));
|
||||
|
||||
const int32_t data[4] = {aBounds.x, aBounds.y, aBounds.x + aBounds.width,
|
||||
aBounds.y + aBounds.height};
|
||||
GECKOBUNDLE_PUT(nodeInfo, "bounds", jni::IntArray::New(data, 4));
|
||||
|
||||
auto childCount = ChildCount();
|
||||
nsTArray<int32_t> children(childCount);
|
||||
for (uint32_t i = 0; i < childCount; ++i) {
|
||||
auto child = static_cast<AccessibleWrap*>(GetChildAt(i));
|
||||
children.AppendElement(child->VirtualViewID());
|
||||
}
|
||||
|
||||
GECKOBUNDLE_PUT(nodeInfo, "children",
|
||||
jni::IntArray::New(children.Elements(), children.Length()));
|
||||
|
||||
GECKOBUNDLE_FINISH(nodeInfo);
|
||||
|
||||
return nodeInfo;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,20 +33,17 @@ class AccessibleWrap : public Accessible {
|
|||
|
||||
virtual bool GetSelectionBounds(int32_t* aStartOffset, int32_t* aEndOffset);
|
||||
|
||||
mozilla::java::GeckoBundle::LocalRef ToBundle();
|
||||
mozilla::java::GeckoBundle::LocalRef ToBundle(bool aSmall = false);
|
||||
|
||||
mozilla::java::GeckoBundle::LocalRef ToBundle(
|
||||
const uint64_t aState, const nsIntRect& aBounds,
|
||||
const uint8_t aActionCount, const nsString& aName,
|
||||
const nsString& aTextValue, const nsString& aDOMNodeID,
|
||||
const double& aCurVal, const double& aMinVal, const double& aMaxVal,
|
||||
const double& aStep, nsIPersistentProperties* aAttributes);
|
||||
|
||||
mozilla::java::GeckoBundle::LocalRef ToSmallBundle(
|
||||
const uint64_t aState, const nsIntRect& aBounds,
|
||||
const uint8_t aActionCount);
|
||||
|
||||
mozilla::java::GeckoBundle::LocalRef ToSmallBundle();
|
||||
const double& aCurVal = UnspecifiedNaN<double>(),
|
||||
const double& aMinVal = UnspecifiedNaN<double>(),
|
||||
const double& aMaxVal = UnspecifiedNaN<double>(),
|
||||
const double& aStep = UnspecifiedNaN<double>(),
|
||||
nsIPersistentProperties* aAttributes = nullptr);
|
||||
|
||||
virtual void WrapperDOMNodeID(nsString& aDOMNodeID);
|
||||
|
||||
|
|
|
|||
|
|
@ -133,10 +133,18 @@ void DocAccessibleWrap::CacheViewportCallback(nsITimer* aTimer,
|
|||
auto uid = accessible->IsDoc() && accessible->AsDoc()->IPCDoc()
|
||||
? 0
|
||||
: reinterpret_cast<uint64_t>(accessible->UniqueID());
|
||||
|
||||
nsAutoString name;
|
||||
accessible->Name(name);
|
||||
nsAutoString textValue;
|
||||
accessible->Value(textValue);
|
||||
nsAutoString nodeID;
|
||||
static_cast<AccessibleWrap*>(accessible)->WrapperDOMNodeID(nodeID);
|
||||
|
||||
cacheData.AppendElement(
|
||||
BatchData(accessible->Document()->IPCDoc(), uid, accessible->State(),
|
||||
accessible->Bounds(), accessible->ActionCount(), nsString(),
|
||||
nsString(), nsString(), UnspecifiedNaN<double>(),
|
||||
accessible->Bounds(), accessible->ActionCount(), name,
|
||||
textValue, nodeID, UnspecifiedNaN<double>(),
|
||||
UnspecifiedNaN<double>(), UnspecifiedNaN<double>(),
|
||||
UnspecifiedNaN<double>(), nsTArray<Attribute>()));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -333,10 +333,11 @@ void SessionAccessibility::ReplaceViewportCache(
|
|||
if (aData.Length() == aAccessibles.Length()) {
|
||||
const BatchData& data = aData.ElementAt(i);
|
||||
auto bundle =
|
||||
acc->ToSmallBundle(data.State(), data.Bounds(), data.ActionCount());
|
||||
acc->ToBundle(data.State(), data.Bounds(), data.ActionCount(),
|
||||
data.Name(), data.TextValue(), data.DOMNodeID());
|
||||
infos->SetElement(i, bundle);
|
||||
} else {
|
||||
infos->SetElement(i, acc->ToSmallBundle());
|
||||
infos->SetElement(i, acc->ToBundle(true));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -380,10 +381,11 @@ void SessionAccessibility::UpdateCachedBounds(
|
|||
if (aData.Length() == aAccessibles.Length()) {
|
||||
const BatchData& data = aData.ElementAt(i);
|
||||
auto bundle =
|
||||
acc->ToSmallBundle(data.State(), data.Bounds(), data.ActionCount());
|
||||
acc->ToBundle(data.State(), data.Bounds(), data.ActionCount(),
|
||||
data.Name(), data.TextValue(), data.DOMNodeID());
|
||||
infos->SetElement(i, bundle);
|
||||
} else {
|
||||
infos->SetElement(i, acc->ToSmallBundle());
|
||||
infos->SetElement(i, acc->ToBundle(true));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -411,6 +411,8 @@ mozilla::ipc::IPCResult DocAccessibleParent::RecvScrollingEvent(
|
|||
#if defined(ANDROID)
|
||||
ProxyScrollingEvent(target, aType, aScrollX, aScrollY, aMaxScrollX,
|
||||
aMaxScrollY);
|
||||
#else
|
||||
ProxyEvent(target, aType);
|
||||
#endif
|
||||
|
||||
if (!nsCoreUtils::AccEventObserversExist()) {
|
||||
|
|
|
|||
|
|
@ -1174,6 +1174,18 @@ pref("services.sync.prefs.sync.browser.ctrlTab.recentlyUsedOrder", true);
|
|||
pref("services.sync.prefs.sync.browser.download.useDownloadDir", true);
|
||||
pref("services.sync.prefs.sync.browser.formfill.enable", true);
|
||||
pref("services.sync.prefs.sync.browser.link.open_newwindow", true);
|
||||
pref("services.sync.prefs.sync.browser.newtabpage.activity-stream.showSearch", true);
|
||||
pref("services.sync.prefs.sync.browser.newtabpage.activity-stream.feeds.topsites", true);
|
||||
pref("services.sync.prefs.sync.browser.newtabpage.activity-stream.topSitesRows", true);
|
||||
pref("services.sync.prefs.sync.browser.newtabpage.activity-stream.feeds.snippets", true);
|
||||
pref("services.sync.prefs.sync.browser.newtabpage.activity-stream.feeds.section.topstories", true);
|
||||
pref("services.sync.prefs.sync.browser.newtabpage.activity-stream.section.topstories.rows", true);
|
||||
pref("services.sync.prefs.sync.browser.newtabpage.activity-stream.feeds.section.highlights", true);
|
||||
pref("services.sync.prefs.sync.browser.newtabpage.activity-stream.section.highlights.includeVisited", true);
|
||||
pref("services.sync.prefs.sync.browser.newtabpage.activity-stream.section.highlights.includeBookmarks", true);
|
||||
pref("services.sync.prefs.sync.browser.newtabpage.activity-stream.section.highlights.includeDownloads", true);
|
||||
pref("services.sync.prefs.sync.browser.newtabpage.activity-stream.section.highlights.includePocket", true);
|
||||
pref("services.sync.prefs.sync.browser.newtabpage.activity-stream.section.highlights.rows", true);
|
||||
pref("services.sync.prefs.sync.browser.newtabpage.enabled", true);
|
||||
pref("services.sync.prefs.sync.browser.newtabpage.pinned", true);
|
||||
pref("services.sync.prefs.sync.browser.offline-apps.notify", true);
|
||||
|
|
|
|||
|
|
@ -492,7 +492,7 @@ window._gBrowser = {
|
|||
},
|
||||
|
||||
set userTypedValue(val) {
|
||||
return this.selectedBrowser.userTypedValue = val;
|
||||
this.selectedBrowser.userTypedValue = val;
|
||||
},
|
||||
|
||||
get userTypedValue() {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@ prefs =
|
|||
browser.migration.version=9999999
|
||||
browser.startup.record=true
|
||||
gfx.canvas.willReadFrequently.enable=true
|
||||
# The form autofill framescript is only used in certain locales if this
|
||||
# pref is set to 'detect', which is the default value on non-Nightly.
|
||||
extensions.formautofill.available='on'
|
||||
support-files =
|
||||
head.js
|
||||
[browser_appmenu.js]
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/* This test records which services, JS components, process scripts, and JS
|
||||
* modules are loaded when creating a new content process.
|
||||
/* This test records which services, JS components, frame scripts, process
|
||||
* scripts, and JS modules are loaded when creating a new content process.
|
||||
*
|
||||
* If you made changes that cause this test to fail, it's likely because you
|
||||
* are loading more JS code during content process startup.
|
||||
|
|
@ -68,6 +68,23 @@ const whitelist = {
|
|||
"resource://gre/modules/ExtensionUtils.jsm",
|
||||
"resource://gre/modules/MessageChannel.jsm",
|
||||
]),
|
||||
frameScripts: new Set([
|
||||
// Test related
|
||||
"resource://specialpowers/MozillaLogger.js",
|
||||
"resource://specialpowers/specialpowersFrameScript.js",
|
||||
"chrome://mochikit/content/shutdown-leaks-collector.js",
|
||||
"chrome://mochikit/content/tests/SimpleTest/AsyncUtilsContent.js",
|
||||
"chrome://mochikit/content/tests/BrowserTestUtils/content-utils.js",
|
||||
|
||||
// Browser front-end
|
||||
"chrome://global/content/browser-content.js",
|
||||
|
||||
// Forms
|
||||
"chrome://formautofill/content/FormAutofillFrameScript.js",
|
||||
|
||||
// Extensions
|
||||
"resource://gre/modules/addons/Content.js",
|
||||
]),
|
||||
processScripts: new Set([
|
||||
"chrome://global/content/process-content.js",
|
||||
"resource:///modules/ContentObservers.js",
|
||||
|
|
@ -89,6 +106,7 @@ const intermittently_loaded_whitelist = {
|
|||
modules: new Set([
|
||||
"resource://gre/modules/sessionstore/Utils.jsm",
|
||||
]),
|
||||
frameScripts: new Set([]),
|
||||
processScripts: new Set([]),
|
||||
};
|
||||
|
||||
|
|
@ -140,6 +158,12 @@ add_task(async function() {
|
|||
|
||||
let loadedInfo = await promise;
|
||||
|
||||
// Gather loaded frame scripts.
|
||||
loadedInfo.frameScripts = {};
|
||||
for (let [uri] of Services.mm.getDelayedFrameScripts()) {
|
||||
loadedInfo.frameScripts[uri] = "";
|
||||
}
|
||||
|
||||
// Gather loaded process scripts.
|
||||
loadedInfo.processScripts = {};
|
||||
for (let [uri] of Services.ppmm.getDelayedProcessScripts()) {
|
||||
|
|
|
|||
|
|
@ -2820,6 +2820,9 @@ void EventStateManager::DecideGestureEvent(WidgetGestureNotifyEvent* aEvent,
|
|||
#ifdef XP_MACOSX
|
||||
static bool NodeAllowsClickThrough(nsINode* aNode) {
|
||||
while (aNode) {
|
||||
if (aNode->IsXULElement(nsGkAtoms::browser)) {
|
||||
return false;
|
||||
}
|
||||
if (aNode->IsXULElement()) {
|
||||
mozilla::dom::Element* element = aNode->AsElement();
|
||||
static Element::AttrValuesArray strings[] = {nsGkAtoms::always,
|
||||
|
|
|
|||
|
|
@ -324,28 +324,30 @@ class MediaRecorder::Session : public PrincipalChangeObserver<MediaStreamTrack>,
|
|||
RefPtr<Session> mSession;
|
||||
};
|
||||
|
||||
// Fire start event and set mimeType, run in main thread task.
|
||||
class DispatchStartEventRunnable : public Runnable {
|
||||
// Fire a named event, run in main thread task.
|
||||
class DispatchEventRunnable : public Runnable {
|
||||
public:
|
||||
explicit DispatchStartEventRunnable(Session* aSession)
|
||||
: Runnable("dom::MediaRecorder::Session::DispatchStartEventRunnable"),
|
||||
mSession(aSession) {}
|
||||
explicit DispatchEventRunnable(Session* aSession,
|
||||
const nsAString& aEventName)
|
||||
: Runnable("dom::MediaRecorder::Session::DispatchEventRunnable"),
|
||||
mSession(aSession),
|
||||
mEventName(aEventName) {}
|
||||
|
||||
NS_IMETHOD Run() override {
|
||||
LOG(LogLevel::Debug,
|
||||
("Session.DispatchStartEventRunnable s=(%p)", mSession.get()));
|
||||
("Session.DispatchEventRunnable s=(%p) e=(%s)", mSession.get(),
|
||||
NS_ConvertUTF16toUTF8(mEventName).get()));
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
NS_ENSURE_TRUE(mSession->mRecorder, NS_OK);
|
||||
RefPtr<MediaRecorder> recorder = mSession->mRecorder;
|
||||
|
||||
recorder->DispatchSimpleEvent(NS_LITERAL_STRING("start"));
|
||||
mSession->mRecorder->DispatchSimpleEvent(mEventName);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<Session> mSession;
|
||||
nsString mEventName;
|
||||
};
|
||||
|
||||
// Main thread task.
|
||||
|
|
@ -591,6 +593,8 @@ class MediaRecorder::Session : public PrincipalChangeObserver<MediaStreamTrack>,
|
|||
}
|
||||
|
||||
mEncoder->Suspend(TimeStamp::Now());
|
||||
NS_DispatchToMainThread(
|
||||
new DispatchEventRunnable(this, NS_LITERAL_STRING("pause")));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
@ -603,6 +607,8 @@ class MediaRecorder::Session : public PrincipalChangeObserver<MediaStreamTrack>,
|
|||
}
|
||||
|
||||
mEncoder->Resume(TimeStamp::Now());
|
||||
NS_DispatchToMainThread(
|
||||
new DispatchEventRunnable(this, NS_LITERAL_STRING("resume")));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
@ -983,7 +989,8 @@ class MediaRecorder::Session : public PrincipalChangeObserver<MediaStreamTrack>,
|
|||
if (mRunningState.isOk() &&
|
||||
(mRunningState.unwrap() == RunningState::Idling ||
|
||||
mRunningState.unwrap() == RunningState::Starting)) {
|
||||
NS_DispatchToMainThread(new DispatchStartEventRunnable(this));
|
||||
NS_DispatchToMainThread(
|
||||
new DispatchEventRunnable(this, NS_LITERAL_STRING("start")));
|
||||
}
|
||||
|
||||
if (rv == NS_OK) {
|
||||
|
|
@ -1050,7 +1057,8 @@ class MediaRecorder::Session : public PrincipalChangeObserver<MediaStreamTrack>,
|
|||
}
|
||||
self->mMimeType = mime;
|
||||
self->mRecorder->SetMimeType(self->mMimeType);
|
||||
auto startEvent = MakeRefPtr<DispatchStartEventRunnable>(self);
|
||||
auto startEvent = MakeRefPtr<DispatchEventRunnable>(
|
||||
self, NS_LITERAL_STRING("start"));
|
||||
startEvent->Run();
|
||||
}
|
||||
}
|
||||
|
|
@ -1323,7 +1331,6 @@ void MediaRecorder::Stop(ErrorResult& aResult) {
|
|||
LOG(LogLevel::Debug, ("MediaRecorder.Stop %p", this));
|
||||
MediaRecorderReporter::RemoveMediaRecorder(this);
|
||||
if (mState == RecordingState::Inactive) {
|
||||
aResult.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
mState = RecordingState::Inactive;
|
||||
|
|
@ -1332,12 +1339,16 @@ void MediaRecorder::Stop(ErrorResult& aResult) {
|
|||
}
|
||||
|
||||
void MediaRecorder::Pause(ErrorResult& aResult) {
|
||||
LOG(LogLevel::Debug, ("MediaRecorder.Pause"));
|
||||
LOG(LogLevel::Debug, ("MediaRecorder.Pause %p", this));
|
||||
if (mState == RecordingState::Inactive) {
|
||||
aResult.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mState == RecordingState::Paused) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mSessions.Length() > 0);
|
||||
nsresult rv = mSessions.LastElement()->Pause();
|
||||
if (NS_FAILED(rv)) {
|
||||
|
|
@ -1346,16 +1357,19 @@ void MediaRecorder::Pause(ErrorResult& aResult) {
|
|||
}
|
||||
|
||||
mState = RecordingState::Paused;
|
||||
DispatchSimpleEvent(NS_LITERAL_STRING("pause"));
|
||||
}
|
||||
|
||||
void MediaRecorder::Resume(ErrorResult& aResult) {
|
||||
LOG(LogLevel::Debug, ("MediaRecorder.Resume"));
|
||||
LOG(LogLevel::Debug, ("MediaRecorder.Resume %p", this));
|
||||
if (mState == RecordingState::Inactive) {
|
||||
aResult.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mState == RecordingState::Recording) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mSessions.Length() > 0);
|
||||
nsresult rv = mSessions.LastElement()->Resume();
|
||||
if (NS_FAILED(rv)) {
|
||||
|
|
@ -1364,7 +1378,6 @@ void MediaRecorder::Resume(ErrorResult& aResult) {
|
|||
}
|
||||
|
||||
mState = RecordingState::Recording;
|
||||
DispatchSimpleEvent(NS_LITERAL_STRING("resume"));
|
||||
}
|
||||
|
||||
void MediaRecorder::RequestData(ErrorResult& aResult) {
|
||||
|
|
@ -1576,15 +1589,12 @@ void MediaRecorder::DispatchSimpleEvent(const nsAString& aStr) {
|
|||
return;
|
||||
}
|
||||
|
||||
RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
|
||||
event->InitEvent(aStr, false, false);
|
||||
event->SetTrusted(true);
|
||||
|
||||
IgnoredErrorResult res;
|
||||
DispatchEvent(*event, res);
|
||||
if (res.Failed()) {
|
||||
rv = DOMEventTargetHelper::DispatchTrustedEvent(aStr);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(LogLevel::Error,
|
||||
("MediaRecorder.DispatchSimpleEvent: DispatchTrustedEvent failed %p",
|
||||
this));
|
||||
NS_ERROR("Failed to dispatch the event!!!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -575,10 +575,10 @@ static void InitInputBuffer(const CDMInputBuffer& aBuffer,
|
|||
aInputBuffer.data_size = aBuffer.mData().Size<uint8_t>();
|
||||
|
||||
if (aBuffer.mEncryptionScheme() > GMPEncryptionScheme::kGMPEncryptionNone) {
|
||||
// Cbcs is not yet supported, so we expect only cenc if the buffer us
|
||||
// encrypted
|
||||
MOZ_ASSERT(aBuffer.mEncryptionScheme() ==
|
||||
GMPEncryptionScheme::kGMPEncryptionCenc);
|
||||
GMPEncryptionScheme::kGMPEncryptionCenc ||
|
||||
aBuffer.mEncryptionScheme() ==
|
||||
GMPEncryptionScheme::kGMPEncryptionCbcs);
|
||||
aInputBuffer.key_id = aBuffer.mKeyId().Elements();
|
||||
aInputBuffer.key_id_size = aBuffer.mKeyId().Length();
|
||||
|
||||
|
|
@ -595,6 +595,8 @@ static void InitInputBuffer(const CDMInputBuffer& aBuffer,
|
|||
aInputBuffer.encryption_scheme =
|
||||
ConvertToCdmEncryptionScheme(aBuffer.mEncryptionScheme());
|
||||
}
|
||||
aInputBuffer.pattern.crypt_byte_block = aBuffer.mCryptByteBlock();
|
||||
aInputBuffer.pattern.skip_byte_block = aBuffer.mSkipByteBlock();
|
||||
aInputBuffer.timestamp = aBuffer.mTimestamp();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -264,15 +264,23 @@ bool ChromiumCDMParent::InitCDMInputBuffer(gmp::CDMInputBuffer& aBuffer,
|
|||
MOZ_ASSERT_UNREACHABLE("Should not have unrecognized encryption type");
|
||||
break;
|
||||
}
|
||||
|
||||
const nsTArray<uint8_t>& iv =
|
||||
encryptionScheme != GMPEncryptionScheme::kGMPEncryptionCbcs
|
||||
? crypto.mIV
|
||||
: crypto.mConstantIV;
|
||||
aBuffer = gmp::CDMInputBuffer(
|
||||
shmem, crypto.mKeyId, crypto.mIV, aSample->mTime.ToMicroseconds(),
|
||||
shmem, crypto.mKeyId, iv, aSample->mTime.ToMicroseconds(),
|
||||
aSample->mDuration.ToMicroseconds(), crypto.mPlainSizes,
|
||||
crypto.mEncryptedSizes, encryptionScheme);
|
||||
crypto.mEncryptedSizes, crypto.mCryptByteBlock, crypto.mSkipByteBlock,
|
||||
encryptionScheme);
|
||||
MOZ_ASSERT(
|
||||
aBuffer.mEncryptionScheme() == GMPEncryptionScheme::kGMPEncryptionNone ||
|
||||
aBuffer.mEncryptionScheme() ==
|
||||
GMPEncryptionScheme::kGMPEncryptionCenc,
|
||||
"aBuffer should use either no encryption or cenc, other kinds are not "
|
||||
GMPEncryptionScheme::kGMPEncryptionCenc ||
|
||||
aBuffer.mEncryptionScheme() ==
|
||||
GMPEncryptionScheme::kGMPEncryptionCbcs,
|
||||
"aBuffer should use no encryption, cenc, or cbcs, other kinds are not "
|
||||
"yet supported");
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,6 +56,8 @@ struct CDMInputBuffer {
|
|||
int64_t mDuration;
|
||||
uint16_t[] mClearBytes;
|
||||
uint32_t[] mCipherBytes;
|
||||
uint8_t mCryptByteBlock;
|
||||
uint8_t mSkipByteBlock;
|
||||
GMPEncryptionScheme mEncryptionScheme;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ var manager = new MediaTestManager;
|
|||
var operationTests = [
|
||||
{
|
||||
operations: ['stop'],
|
||||
isValid: false
|
||||
isValid: true
|
||||
},
|
||||
{
|
||||
operations: ['requestData'],
|
||||
|
|
@ -70,7 +70,7 @@ var operationTests = [
|
|||
},
|
||||
{
|
||||
operations: ['stop', 'start'],
|
||||
isValid: false
|
||||
isValid: true
|
||||
},
|
||||
{
|
||||
operations: ['start', 'stop'],
|
||||
|
|
@ -156,7 +156,7 @@ var operationTests = [
|
|||
},
|
||||
{
|
||||
operations: ['start', 'stop', 'stop'],
|
||||
isValid: false
|
||||
isValid: true
|
||||
},
|
||||
{
|
||||
operations: ['start', 'pause', 'resume', 'resume'],
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "mozilla/gfx/Logging.h"
|
||||
#include "nsITimer.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "VRGPUChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
|
@ -150,6 +151,9 @@ void GPUProcessHost::Shutdown() {
|
|||
|
||||
// The channel might already be closed if we got here unexpectedly.
|
||||
if (!mChannelClosed) {
|
||||
if (VRGPUChild::IsCreated()) {
|
||||
VRGPUChild::Get()->Close();
|
||||
}
|
||||
mGPUChild->SendShutdownVR();
|
||||
mGPUChild->Close();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -378,7 +378,7 @@ class gfxPrefs final {
|
|||
DECL_GFX_PREF(Once, "dom.vr.enabled", VREnabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "dom.vr.autoactivate.enabled", VRAutoActivateEnabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "dom.vr.controller_trigger_threshold", VRControllerTriggerThreshold, float, 0.1f);
|
||||
DECL_GFX_PREF(Once, "dom.vr.external.enabled", VRExternalEnabled, bool, true);
|
||||
DECL_GFX_PREF(Once, "dom.vr.external.enabled", VRExternalEnabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "dom.vr.external.notdetected.timeout", VRExternalNotDetectedTimeout, int32_t, 60000);
|
||||
DECL_GFX_PREF(Live, "dom.vr.external.quit.timeout", VRExternalQuitTimeout, int32_t, 10000);
|
||||
DECL_GFX_PREF(Live, "dom.vr.navigation.timeout", VRNavigationTimeout, int32_t, 1000);
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ VRManager::VRManager()
|
|||
#if !defined(MOZ_WIDGET_ANDROID)
|
||||
// The VR Service accesses all hardware from a separate process
|
||||
// and replaces the other VRSystemManager when enabled.
|
||||
if (!gfxPrefs::VRProcessEnabled()) {
|
||||
if (!gfxPrefs::VRProcessEnabled() || !XRE_IsGPUProcess()) {
|
||||
VRServiceManager::Get().CreateService();
|
||||
}
|
||||
if (VRServiceManager::Get().IsServiceValid()) {
|
||||
|
|
@ -127,6 +127,7 @@ void VRManager::Destroy() {
|
|||
VRServiceManager::Get().Shutdown();
|
||||
}
|
||||
#endif
|
||||
Shutdown();
|
||||
mInitialized = false;
|
||||
}
|
||||
|
||||
|
|
@ -140,7 +141,9 @@ void VRManager::Shutdown() {
|
|||
if (VRServiceManager::Get().IsServiceValid()) {
|
||||
VRServiceManager::Get().Stop();
|
||||
}
|
||||
if (gfxPrefs::VRProcessEnabled() && mVRServiceStarted) {
|
||||
// XRE_IsGPUProcess() is helping us to check some platforms like
|
||||
// Win 7 try which are not using GPU process but VR process is enabled.
|
||||
if (XRE_IsGPUProcess() && gfxPrefs::VRProcessEnabled() && mVRServiceStarted) {
|
||||
RefPtr<Runnable> task = NS_NewRunnableFunction(
|
||||
"VRServiceManager::ShutdownVRProcess",
|
||||
[]() -> void { VRServiceManager::Get().ShutdownVRProcess(); });
|
||||
|
|
@ -435,13 +438,15 @@ void VRManager::EnumerateVRDisplays() {
|
|||
* is in progress
|
||||
*/
|
||||
#if !defined(MOZ_WIDGET_ANDROID)
|
||||
if (gfxPrefs::VRProcessEnabled() && !mVRServiceStarted) {
|
||||
VRServiceManager::Get().CreateVRProcess();
|
||||
mVRServiceStarted = true;
|
||||
} else if (!gfxPrefs::VRProcessEnabled()) {
|
||||
if (VRServiceManager::Get().IsServiceValid()) {
|
||||
VRServiceManager::Get().Start();
|
||||
if (!mVRServiceStarted) {
|
||||
if (XRE_IsGPUProcess() && gfxPrefs::VRProcessEnabled()) {
|
||||
VRServiceManager::Get().CreateVRProcess();
|
||||
mVRServiceStarted = true;
|
||||
} else {
|
||||
if (VRServiceManager::Get().IsServiceValid()) {
|
||||
VRServiceManager::Get().Start();
|
||||
mVRServiceStarted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -486,7 +486,8 @@ void VRSystemManagerExternal::OpenShmem() {
|
|||
mShmemFile =
|
||||
CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
|
||||
sizeof(VRExternalShmem), kShmemName);
|
||||
MOZ_ASSERT(GetLastError() == 0);
|
||||
MOZ_ASSERT(GetLastError() == 0 || GetLastError() == ERROR_ALREADY_EXISTS);
|
||||
MOZ_ASSERT(mShmemFile);
|
||||
} else {
|
||||
mShmemFile = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, kShmemName);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,8 +42,19 @@ static StaticRefPtr<VRGPUChild> sVRGPUChildSingleton;
|
|||
|
||||
/*static*/ void VRGPUChild::Shutdown() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (sVRGPUChildSingleton && !sVRGPUChildSingleton->IsClosed()) {
|
||||
sVRGPUChildSingleton->Close();
|
||||
}
|
||||
sVRGPUChildSingleton = nullptr;
|
||||
}
|
||||
|
||||
void VRGPUChild::ActorDestroy(ActorDestroyReason aWhy) {
|
||||
mClosed = true;
|
||||
}
|
||||
|
||||
bool VRGPUChild::IsClosed() {
|
||||
return mClosed;
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
|
|
|||
|
|
@ -21,12 +21,17 @@ class VRGPUChild final : public PVRGPUChild {
|
|||
static bool IsCreated();
|
||||
static void Shutdown();
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
bool IsClosed();
|
||||
|
||||
protected:
|
||||
explicit VRGPUChild() {}
|
||||
~VRGPUChild() {}
|
||||
explicit VRGPUChild() : mClosed(false) {}
|
||||
~VRGPUChild() = default;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(VRGPUChild);
|
||||
|
||||
bool mClosed;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
|
|
|
|||
|
|
@ -13,13 +13,18 @@ namespace gfx {
|
|||
|
||||
using namespace ipc;
|
||||
|
||||
VRGPUParent::VRGPUParent(ProcessId aChildProcessId) {
|
||||
VRGPUParent::VRGPUParent(ProcessId aChildProcessId)
|
||||
: mClosed(false) {
|
||||
MOZ_COUNT_CTOR(VRGPUParent);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
SetOtherProcessId(aChildProcessId);
|
||||
}
|
||||
|
||||
VRGPUParent::~VRGPUParent() {
|
||||
MOZ_COUNT_DTOR(VRGPUParent);
|
||||
}
|
||||
|
||||
void VRGPUParent::ActorDestroy(ActorDestroyReason aWhy) {
|
||||
#if !defined(MOZ_WIDGET_ANDROID)
|
||||
if (mVRService) {
|
||||
|
|
@ -28,6 +33,7 @@ void VRGPUParent::ActorDestroy(ActorDestroyReason aWhy) {
|
|||
}
|
||||
#endif
|
||||
|
||||
mClosed = true;
|
||||
MessageLoop::current()->PostTask(
|
||||
NewRunnableMethod("gfx::VRGPUParent::DeferredDestroy", this,
|
||||
&VRGPUParent::DeferredDestroy));
|
||||
|
|
@ -41,7 +47,7 @@ void VRGPUParent::DeferredDestroy() { mSelfRef = nullptr; }
|
|||
MessageLoop::current()->PostTask(NewRunnableMethod<Endpoint<PVRGPUParent>&&>(
|
||||
"gfx::VRGPUParent::Bind", vcp, &VRGPUParent::Bind, std::move(aEndpoint)));
|
||||
|
||||
return vcp;
|
||||
return vcp.forget();
|
||||
}
|
||||
|
||||
void VRGPUParent::Bind(Endpoint<PVRGPUParent>&& aEndpoint) {
|
||||
|
|
@ -74,5 +80,9 @@ mozilla::ipc::IPCResult VRGPUParent::RecvStopVRService() {
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
bool VRGPUParent::IsClosed() {
|
||||
return mClosed;
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
|
@ -17,25 +17,28 @@ class VRGPUParent final : public PVRGPUParent {
|
|||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRGPUParent)
|
||||
|
||||
public:
|
||||
explicit VRGPUParent(ProcessId aChildProcessId);
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
static RefPtr<VRGPUParent> CreateForGPU(Endpoint<PVRGPUParent>&& aEndpoint);
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
bool IsClosed();
|
||||
|
||||
protected:
|
||||
~VRGPUParent() = default;
|
||||
|
||||
void Bind(Endpoint<PVRGPUParent>&& aEndpoint);
|
||||
virtual mozilla::ipc::IPCResult RecvStartVRService() override;
|
||||
virtual mozilla::ipc::IPCResult RecvStopVRService() override;
|
||||
|
||||
private:
|
||||
explicit VRGPUParent(ProcessId aChildProcessId);
|
||||
~VRGPUParent();
|
||||
|
||||
void DeferredDestroy();
|
||||
|
||||
RefPtr<VRGPUParent> mSelfRef;
|
||||
#if !defined(MOZ_WIDGET_ANDROID)
|
||||
RefPtr<VRService> mVRService;
|
||||
#endif
|
||||
bool mClosed;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(VRGPUParent);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include "VRGPUParent.h"
|
||||
#include "VRManager.h"
|
||||
#include "gfxConfig.h"
|
||||
#include "nsDebugImpl.h"
|
||||
|
||||
#include "mozilla/gfx/gfxVars.h"
|
||||
#include "mozilla/ipc/ProcessChild.h"
|
||||
|
|
@ -96,6 +97,9 @@ void VRParent::ActorDestroy(ActorDestroyReason aWhy) {
|
|||
NS_WARNING("Shutting down VR process early due to a crash!");
|
||||
ProcessChild::QuickExit();
|
||||
}
|
||||
if (!mVRGPUParent->IsClosed()) {
|
||||
mVRGPUParent->Close();
|
||||
}
|
||||
|
||||
mVRGPUParent = nullptr;
|
||||
#if defined(XP_WIN)
|
||||
|
|
@ -123,6 +127,8 @@ bool VRParent::Init(base::ProcessId aParentPid, const char* aParentBuildID,
|
|||
return false;
|
||||
}
|
||||
|
||||
nsDebugImpl::SetMultiprocessMode("VR");
|
||||
|
||||
// This must be checked before any IPDL message, which may hit sentinel
|
||||
// errors due to parent and content processes having different
|
||||
// versions.
|
||||
|
|
|
|||
|
|
@ -26,8 +26,6 @@ VRProcessChild::~VRProcessChild() { sVRParent = nullptr; }
|
|||
}
|
||||
|
||||
bool VRProcessChild::Init(int aArgc, char* aArgv[]) {
|
||||
BackgroundHangMonitor::Startup();
|
||||
|
||||
char* parentBuildID = nullptr;
|
||||
for (int i = 1; i < aArgc; i++) {
|
||||
if (!aArgv[i]) {
|
||||
|
|
|
|||
|
|
@ -206,6 +206,10 @@ OculusSession::OculusSession()
|
|||
OculusSession::~OculusSession() { Shutdown(); }
|
||||
|
||||
bool OculusSession::Initialize(mozilla::gfx::VRSystemState& aSystemState) {
|
||||
if (!gfxPrefs::VREnabled() || !gfxPrefs::VROculusEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CreateD3DObjects()) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -530,14 +534,18 @@ bool OculusSession::LoadOvrLib() {
|
|||
nsString libName;
|
||||
nsString searchPath;
|
||||
|
||||
static const char dirSep = '\\';
|
||||
static const int pathLen = 260;
|
||||
searchPath.SetCapacity(pathLen);
|
||||
int realLen =
|
||||
::GetSystemDirectoryW(char16ptr_t(searchPath.BeginWriting()), pathLen);
|
||||
if (realLen != 0 && realLen < pathLen) {
|
||||
searchPath.SetLength(realLen);
|
||||
libSearchPaths.AppendElement(searchPath);
|
||||
for (;;) {
|
||||
UINT requiredLength = ::GetSystemDirectoryW(
|
||||
char16ptr_t(searchPath.BeginWriting()), searchPath.Length());
|
||||
if (!requiredLength) {
|
||||
break;
|
||||
}
|
||||
if (requiredLength < searchPath.Length()) {
|
||||
searchPath.Truncate(requiredLength);
|
||||
libSearchPaths.AppendElement(searchPath);
|
||||
break;
|
||||
}
|
||||
searchPath.SetLength(requiredLength);
|
||||
}
|
||||
libName.AppendPrintf("LibOVRRT%d_%d.dll", BUILD_BITS, OVR_PRODUCT_VERSION);
|
||||
|
||||
|
|
@ -554,13 +562,17 @@ bool OculusSession::LoadOvrLib() {
|
|||
libName = _wgetenv(L"OVR_LIB_NAME");
|
||||
}
|
||||
|
||||
if (libName.IsEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < libSearchPaths.Length(); ++i) {
|
||||
nsString& libPath = libSearchPaths[i];
|
||||
nsString fullName;
|
||||
if (libPath.Length() == 0) {
|
||||
fullName.Assign(libName);
|
||||
} else {
|
||||
fullName.AppendPrintf("%s%c%s", libPath.get(), dirSep, libName.get());
|
||||
fullName.Assign(libPath + NS_LITERAL_STRING(u"\\") + libName);
|
||||
}
|
||||
|
||||
mOvrLib = LoadLibraryWithFlags(fullName.get());
|
||||
|
|
|
|||
|
|
@ -40,7 +40,9 @@ void VRServiceManager::ShutdownVRProcess() {
|
|||
if (VRGPUChild::IsCreated()) {
|
||||
VRGPUChild* vrGPUChild = VRGPUChild::Get();
|
||||
vrGPUChild->SendStopVRService();
|
||||
vrGPUChild->Close();
|
||||
if (!vrGPUChild->IsClosed()) {
|
||||
vrGPUChild->Close();
|
||||
}
|
||||
VRGPUChild::Shutdown();
|
||||
}
|
||||
if (gfxPrefs::VRProcessEnabled()) {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use gpu_types::{PrimitiveInstanceData, RasterizationSpace, GlyphInstance};
|
|||
use gpu_types::{PrimitiveHeader, PrimitiveHeaderIndex, TransformPaletteId, TransformPalette};
|
||||
use internal_types::{FastHashMap, SavedTargetIndex, TextureSource};
|
||||
use picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive, PictureSurface};
|
||||
use prim_store::{DeferredResolve, EdgeAaSegmentMask, PrimitiveInstanceKind};
|
||||
use prim_store::{DeferredResolve, EdgeAaSegmentMask, PrimitiveInstanceKind, PrimitiveVisibilityIndex};
|
||||
use prim_store::{VisibleGradientTile, PrimitiveInstance, PrimitiveOpacity, SegmentInstanceIndex};
|
||||
use prim_store::{BrushSegment, ClipMaskKind, ClipTaskIndex};
|
||||
use prim_store::image::ImageSource;
|
||||
|
|
@ -583,7 +583,7 @@ impl AlphaBatchBuilder {
|
|||
root_spatial_node_index: SpatialNodeIndex,
|
||||
z_generator: &mut ZBufferIdGenerator,
|
||||
) {
|
||||
if prim_instance.bounding_rect.is_none() {
|
||||
if prim_instance.visibility_info == PrimitiveVisibilityIndex::INVALID {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -601,15 +601,15 @@ impl AlphaBatchBuilder {
|
|||
// wasteful. We should probably cache this in
|
||||
// the scroll node...
|
||||
let transform_kind = transform_id.transform_kind();
|
||||
let bounding_rect = prim_instance.bounding_rect
|
||||
.as_ref()
|
||||
.expect("bug");
|
||||
let prim_info = &ctx.scratch.prim_info[prim_instance.visibility_info.0 as usize];
|
||||
let bounding_rect = &prim_info.clip_chain.pic_clip_rect;
|
||||
|
||||
let z_id = z_generator.next();
|
||||
|
||||
// Get the clip task address for the global primitive, if one was set.
|
||||
let clip_task_address = get_clip_task_address(
|
||||
&ctx.scratch.clip_mask_instances,
|
||||
prim_instance.clip_task_index,
|
||||
prim_info.clip_task_index,
|
||||
0,
|
||||
render_tasks,
|
||||
).unwrap_or(OPAQUE_TASK_ADDRESS);
|
||||
|
|
@ -631,7 +631,7 @@ impl AlphaBatchBuilder {
|
|||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_instance.combined_local_clip_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
task_address,
|
||||
specific_prim_address: prim_cache_address,
|
||||
clip_task_address,
|
||||
|
|
@ -691,7 +691,7 @@ impl AlphaBatchBuilder {
|
|||
}
|
||||
|
||||
let non_segmented_blend_mode = if !common_data.opacity.is_opaque ||
|
||||
prim_instance.clip_task_index != ClipTaskIndex::INVALID ||
|
||||
prim_info.clip_task_index != ClipTaskIndex::INVALID ||
|
||||
transform_kind == TransformedRectKind::Complex
|
||||
{
|
||||
specified_blend_mode
|
||||
|
|
@ -701,7 +701,7 @@ impl AlphaBatchBuilder {
|
|||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_instance.combined_local_clip_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
task_address,
|
||||
specific_prim_address: prim_cache_address,
|
||||
clip_task_address,
|
||||
|
|
@ -737,7 +737,7 @@ impl AlphaBatchBuilder {
|
|||
transform_kind,
|
||||
render_tasks,
|
||||
z_id,
|
||||
prim_instance.clip_task_index,
|
||||
prim_info.clip_task_index,
|
||||
ctx,
|
||||
);
|
||||
}
|
||||
|
|
@ -754,7 +754,7 @@ impl AlphaBatchBuilder {
|
|||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_instance.combined_local_clip_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
task_address,
|
||||
specific_prim_address: prim_cache_address,
|
||||
clip_task_address,
|
||||
|
|
@ -891,7 +891,7 @@ impl AlphaBatchBuilder {
|
|||
// helper methods, as we port more primitives to make
|
||||
// use of interning.
|
||||
let blend_mode = if !common_data.opacity.is_opaque ||
|
||||
prim_instance.clip_task_index != ClipTaskIndex::INVALID ||
|
||||
prim_info.clip_task_index != ClipTaskIndex::INVALID ||
|
||||
transform_kind == TransformedRectKind::Complex
|
||||
{
|
||||
BlendMode::PremultipliedAlpha
|
||||
|
|
@ -901,7 +901,7 @@ impl AlphaBatchBuilder {
|
|||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_instance.combined_local_clip_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
task_address,
|
||||
specific_prim_address: prim_cache_address,
|
||||
clip_task_address,
|
||||
|
|
@ -943,7 +943,7 @@ impl AlphaBatchBuilder {
|
|||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: picture.local_rect,
|
||||
local_clip_rect: prim_instance.combined_local_clip_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
task_address,
|
||||
specific_prim_address: prim_cache_address,
|
||||
clip_task_address,
|
||||
|
|
@ -955,6 +955,8 @@ impl AlphaBatchBuilder {
|
|||
Picture3DContext::In { root_data: Some(ref list), .. } => {
|
||||
for child in list {
|
||||
let prim_instance = &picture.prim_list.prim_instances[child.anchor];
|
||||
let prim_info = &ctx.scratch.prim_info[prim_instance.visibility_info.0 as usize];
|
||||
|
||||
let pic_index = match prim_instance.kind {
|
||||
PrimitiveInstanceKind::Picture { pic_index, .. } => pic_index,
|
||||
PrimitiveInstanceKind::LineDecoration { .. } |
|
||||
|
|
@ -972,17 +974,18 @@ impl AlphaBatchBuilder {
|
|||
};
|
||||
let pic = &ctx.prim_store.pictures[pic_index.0];
|
||||
|
||||
|
||||
// Get clip task, if set, for the picture primitive.
|
||||
let clip_task_address = get_clip_task_address(
|
||||
&ctx.scratch.clip_mask_instances,
|
||||
prim_instance.clip_task_index,
|
||||
prim_info.clip_task_index,
|
||||
0,
|
||||
render_tasks,
|
||||
).unwrap_or(OPAQUE_TASK_ADDRESS);
|
||||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: pic.local_rect,
|
||||
local_clip_rect: prim_instance.combined_local_clip_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
task_address,
|
||||
specific_prim_address: GpuCacheAddress::invalid(),
|
||||
clip_task_address,
|
||||
|
|
@ -1025,7 +1028,7 @@ impl AlphaBatchBuilder {
|
|||
|
||||
self.current_batch_list().push_single_instance(
|
||||
key,
|
||||
&prim_instance.bounding_rect.as_ref().expect("bug"),
|
||||
&prim_info.clip_chain.pic_clip_rect,
|
||||
z_id,
|
||||
PrimitiveInstanceData::from(instance),
|
||||
);
|
||||
|
|
@ -1044,7 +1047,7 @@ impl AlphaBatchBuilder {
|
|||
PictureCompositeMode::TileCache { .. } => {
|
||||
// Construct a local clip rect that ensures we only draw pixels where
|
||||
// the local bounds of the picture extend to within the edge tiles.
|
||||
let local_clip_rect = prim_instance
|
||||
let local_clip_rect = prim_info
|
||||
.combined_local_clip_rect
|
||||
.intersection(&picture.local_rect)
|
||||
.and_then(|rect| {
|
||||
|
|
@ -1503,7 +1506,7 @@ impl AlphaBatchBuilder {
|
|||
let prim_cache_address = gpu_cache.get_address(&common_data.gpu_cache_handle);
|
||||
let specified_blend_mode = BlendMode::PremultipliedAlpha;
|
||||
let non_segmented_blend_mode = if !common_data.opacity.is_opaque ||
|
||||
prim_instance.clip_task_index != ClipTaskIndex::INVALID ||
|
||||
prim_info.clip_task_index != ClipTaskIndex::INVALID ||
|
||||
transform_kind == TransformedRectKind::Complex
|
||||
{
|
||||
specified_blend_mode
|
||||
|
|
@ -1513,7 +1516,7 @@ impl AlphaBatchBuilder {
|
|||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_instance.combined_local_clip_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
task_address,
|
||||
specific_prim_address: prim_cache_address,
|
||||
clip_task_address,
|
||||
|
|
@ -1549,7 +1552,7 @@ impl AlphaBatchBuilder {
|
|||
transform_kind,
|
||||
render_tasks,
|
||||
z_id,
|
||||
prim_instance.clip_task_index,
|
||||
prim_info.clip_task_index,
|
||||
ctx,
|
||||
);
|
||||
}
|
||||
|
|
@ -1562,7 +1565,7 @@ impl AlphaBatchBuilder {
|
|||
let opacity = opacity.combine(prim_data.opacity);
|
||||
|
||||
let non_segmented_blend_mode = if !opacity.is_opaque ||
|
||||
prim_instance.clip_task_index != ClipTaskIndex::INVALID ||
|
||||
prim_info.clip_task_index != ClipTaskIndex::INVALID ||
|
||||
transform_kind == TransformedRectKind::Complex
|
||||
{
|
||||
specified_blend_mode
|
||||
|
|
@ -1587,7 +1590,7 @@ impl AlphaBatchBuilder {
|
|||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_instance.combined_local_clip_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
task_address,
|
||||
specific_prim_address: prim_cache_address,
|
||||
clip_task_address,
|
||||
|
|
@ -1612,7 +1615,7 @@ impl AlphaBatchBuilder {
|
|||
transform_kind,
|
||||
render_tasks,
|
||||
z_id,
|
||||
prim_instance.clip_task_index,
|
||||
prim_info.clip_task_index,
|
||||
ctx,
|
||||
);
|
||||
}
|
||||
|
|
@ -1676,7 +1679,7 @@ impl AlphaBatchBuilder {
|
|||
let specified_blend_mode = BlendMode::PremultipliedAlpha;
|
||||
|
||||
let non_segmented_blend_mode = if !prim_common_data.opacity.is_opaque ||
|
||||
prim_instance.clip_task_index != ClipTaskIndex::INVALID ||
|
||||
prim_info.clip_task_index != ClipTaskIndex::INVALID ||
|
||||
transform_kind == TransformedRectKind::Complex
|
||||
{
|
||||
specified_blend_mode
|
||||
|
|
@ -1695,7 +1698,7 @@ impl AlphaBatchBuilder {
|
|||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_instance.combined_local_clip_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
task_address,
|
||||
specific_prim_address: prim_cache_address,
|
||||
clip_task_address,
|
||||
|
|
@ -1720,7 +1723,7 @@ impl AlphaBatchBuilder {
|
|||
transform_kind,
|
||||
render_tasks,
|
||||
z_id,
|
||||
prim_instance.clip_task_index,
|
||||
prim_info.clip_task_index,
|
||||
ctx,
|
||||
);
|
||||
}
|
||||
|
|
@ -1769,7 +1772,7 @@ impl AlphaBatchBuilder {
|
|||
let opacity = opacity.combine(common_data.opacity);
|
||||
|
||||
let non_segmented_blend_mode = if !opacity.is_opaque ||
|
||||
prim_instance.clip_task_index != ClipTaskIndex::INVALID ||
|
||||
prim_info.clip_task_index != ClipTaskIndex::INVALID ||
|
||||
transform_kind == TransformedRectKind::Complex
|
||||
{
|
||||
specified_blend_mode
|
||||
|
|
@ -1799,7 +1802,7 @@ impl AlphaBatchBuilder {
|
|||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_instance.combined_local_clip_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
task_address,
|
||||
specific_prim_address: prim_cache_address,
|
||||
clip_task_address,
|
||||
|
|
@ -1824,7 +1827,7 @@ impl AlphaBatchBuilder {
|
|||
transform_kind,
|
||||
render_tasks,
|
||||
z_id,
|
||||
prim_instance.clip_task_index,
|
||||
prim_info.clip_task_index,
|
||||
ctx,
|
||||
);
|
||||
} else {
|
||||
|
|
@ -1869,7 +1872,7 @@ impl AlphaBatchBuilder {
|
|||
|
||||
let mut prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_instance.combined_local_clip_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
task_address,
|
||||
specific_prim_address: GpuCacheAddress::invalid(),
|
||||
clip_task_address,
|
||||
|
|
@ -1878,7 +1881,7 @@ impl AlphaBatchBuilder {
|
|||
|
||||
if visible_tiles_range.is_empty() {
|
||||
let non_segmented_blend_mode = if !prim_data.opacity.is_opaque ||
|
||||
prim_instance.clip_task_index != ClipTaskIndex::INVALID ||
|
||||
prim_info.clip_task_index != ClipTaskIndex::INVALID ||
|
||||
transform_kind == TransformedRectKind::Complex
|
||||
{
|
||||
specified_blend_mode
|
||||
|
|
@ -1923,7 +1926,7 @@ impl AlphaBatchBuilder {
|
|||
transform_kind,
|
||||
render_tasks,
|
||||
z_id,
|
||||
prim_instance.clip_task_index,
|
||||
prim_info.clip_task_index,
|
||||
ctx,
|
||||
);
|
||||
} else {
|
||||
|
|
@ -1950,7 +1953,7 @@ impl AlphaBatchBuilder {
|
|||
|
||||
let mut prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_instance.combined_local_clip_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
task_address,
|
||||
specific_prim_address: GpuCacheAddress::invalid(),
|
||||
clip_task_address,
|
||||
|
|
@ -1959,7 +1962,7 @@ impl AlphaBatchBuilder {
|
|||
|
||||
if visible_tiles_range.is_empty() {
|
||||
let non_segmented_blend_mode = if !prim_data.opacity.is_opaque ||
|
||||
prim_instance.clip_task_index != ClipTaskIndex::INVALID ||
|
||||
prim_info.clip_task_index != ClipTaskIndex::INVALID ||
|
||||
transform_kind == TransformedRectKind::Complex
|
||||
{
|
||||
specified_blend_mode
|
||||
|
|
@ -2004,7 +2007,7 @@ impl AlphaBatchBuilder {
|
|||
transform_kind,
|
||||
render_tasks,
|
||||
z_id,
|
||||
prim_instance.clip_task_index,
|
||||
prim_info.clip_task_index,
|
||||
ctx,
|
||||
);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -462,6 +462,21 @@ pub struct ClipChainInstance {
|
|||
pub pic_clip_rect: PictureRect,
|
||||
}
|
||||
|
||||
impl ClipChainInstance {
|
||||
pub fn empty() -> Self {
|
||||
ClipChainInstance {
|
||||
clips_range: ClipNodeRange {
|
||||
first: 0,
|
||||
count: 0,
|
||||
},
|
||||
local_clip_rect: LayoutRect::zero(),
|
||||
has_non_local_clips: false,
|
||||
needs_mask: false,
|
||||
pic_clip_rect: PictureRect::zero(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ClipStore {
|
||||
pub fn new() -> Self {
|
||||
ClipStore {
|
||||
|
|
|
|||
|
|
@ -70,6 +70,20 @@ pub struct FrameBuilder {
|
|||
pub config: FrameBuilderConfig,
|
||||
}
|
||||
|
||||
pub struct FrameVisibilityContext<'a> {
|
||||
pub clip_scroll_tree: &'a ClipScrollTree,
|
||||
pub screen_world_rect: WorldRect,
|
||||
pub device_pixel_scale: DevicePixelScale,
|
||||
pub surfaces: &'a [SurfaceInfo],
|
||||
}
|
||||
|
||||
pub struct FrameVisibilityState<'a> {
|
||||
pub clip_store: &'a mut ClipStore,
|
||||
pub resource_cache: &'a mut ResourceCache,
|
||||
pub gpu_cache: &'a mut GpuCache,
|
||||
pub scratch: &'a mut PrimitiveScratchBuffer,
|
||||
}
|
||||
|
||||
pub struct FrameBuildingContext<'a> {
|
||||
pub device_pixel_scale: DevicePixelScale,
|
||||
pub scene_properties: &'a SceneProperties,
|
||||
|
|
@ -198,6 +212,16 @@ impl FrameBuilder {
|
|||
self.prim_store.destroy(
|
||||
retained_tiles,
|
||||
);
|
||||
|
||||
// In general, the pending retained tiles are consumed by the frame
|
||||
// builder the first time a frame is built after a new scene has
|
||||
// arrived. However, if two scenes arrive in quick succession, the
|
||||
// frame builder may not have had a chance to build a frame and
|
||||
// consume the pending tiles. In this case, the pending tiles will
|
||||
// be lost, causing a full invalidation of the entire screen. To
|
||||
// avoid this, if there are still pending tiles, include them in
|
||||
// the retained tiles passed to the next frame builder.
|
||||
retained_tiles.tiles.extend(self.pending_retained_tiles.tiles);
|
||||
}
|
||||
|
||||
/// Compute the contribution (bounding rectangles, and resources) of layers and their
|
||||
|
|
@ -295,6 +319,30 @@ impl FrameBuilder {
|
|||
scratch,
|
||||
);
|
||||
|
||||
{
|
||||
let visibility_context = FrameVisibilityContext {
|
||||
device_pixel_scale,
|
||||
clip_scroll_tree,
|
||||
screen_world_rect,
|
||||
surfaces: pic_update_state.surfaces,
|
||||
};
|
||||
|
||||
let mut visibility_state = FrameVisibilityState {
|
||||
resource_cache,
|
||||
gpu_cache,
|
||||
clip_store: &mut self.clip_store,
|
||||
scratch,
|
||||
};
|
||||
|
||||
self.prim_store.update_visibility(
|
||||
self.root_pic_index,
|
||||
ROOT_SURFACE_INDEX,
|
||||
&visibility_context,
|
||||
&mut visibility_state,
|
||||
resources,
|
||||
);
|
||||
}
|
||||
|
||||
let mut frame_state = FrameBuildingState {
|
||||
render_tasks,
|
||||
profile_counters,
|
||||
|
|
@ -336,7 +384,6 @@ impl FrameBuilder {
|
|||
prim_list,
|
||||
pic_context,
|
||||
pic_state,
|
||||
&mut frame_state,
|
||||
);
|
||||
|
||||
let child_tasks = frame_state
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use api::{PicturePixel, RasterPixel, WorldPixel, WorldRect, ImageFormat, ImageDe
|
|||
#[cfg(feature = "debug_renderer")]
|
||||
use api::{DebugFlags, DeviceVector2D};
|
||||
use box_shadow::{BLUR_SAMPLE_SCALE};
|
||||
use clip::{ClipNodeCollector, ClipStore, ClipChainId, ClipChainNode, ClipItem};
|
||||
use clip::{ClipStore, ClipChainId, ClipChainNode, ClipItem};
|
||||
use clip_scroll_tree::{ROOT_SPATIAL_NODE_INDEX, ClipScrollTree, SpatialNodeIndex, CoordinateSystemId};
|
||||
#[cfg(feature = "debug_renderer")]
|
||||
use debug_colors;
|
||||
|
|
@ -24,7 +24,7 @@ use gpu_types::{TransformPalette, TransformPaletteId, UvRectKind};
|
|||
use plane_split::{Clipper, Polygon, Splitter};
|
||||
use prim_store::{PictureIndex, PrimitiveInstance, SpaceMapper, VisibleFace, PrimitiveInstanceKind};
|
||||
use prim_store::{get_raster_rects, CoordinateSpaceMapping, PrimitiveScratchBuffer};
|
||||
use prim_store::{OpacityBindingStorage, ImageInstanceStorage, OpacityBindingIndex};
|
||||
use prim_store::{OpacityBindingStorage, ImageInstanceStorage, OpacityBindingIndex, RectangleKey};
|
||||
use print_tree::PrintTreePrinter;
|
||||
use render_backend::FrameResources;
|
||||
use render_task::{ClearMode, RenderTask, RenderTaskCacheEntryHandle, TileBlit};
|
||||
|
|
@ -135,6 +135,9 @@ pub struct Tile {
|
|||
/// The currently visible rect within this tile, updated per frame.
|
||||
/// If None, this tile is not currently visible.
|
||||
visible_rect: Option<WorldRect>,
|
||||
/// The currently valid rect of the tile, used to invalidate
|
||||
/// tiles that were only partially drawn.
|
||||
valid_rect: WorldRect,
|
||||
/// Uniquely describes the content of this tile, in a way that can be
|
||||
/// (reasonably) efficiently hashed and compared.
|
||||
descriptor: TileDescriptor,
|
||||
|
|
@ -155,6 +158,10 @@ pub struct Tile {
|
|||
/// care about. Stored as a set here, and then collected, sorted
|
||||
/// and converted to transform key values during post_update.
|
||||
transforms: FastHashSet<SpatialNodeIndex>,
|
||||
/// A list of potentially important clips. We can't know if
|
||||
/// they were important or can be discarded until we know the
|
||||
/// tile cache bounding rect.
|
||||
potential_clips: FastHashMap<RectangleKey, SpatialNodeIndex>,
|
||||
}
|
||||
|
||||
impl Tile {
|
||||
|
|
@ -166,12 +173,14 @@ impl Tile {
|
|||
local_rect: LayoutRect::zero(),
|
||||
world_rect: WorldRect::zero(),
|
||||
visible_rect: None,
|
||||
valid_rect: WorldRect::zero(),
|
||||
handle: TextureCacheHandle::invalid(),
|
||||
descriptor: TileDescriptor::new(),
|
||||
is_same_content: false,
|
||||
is_valid: false,
|
||||
same_frames: 0,
|
||||
transforms: FastHashSet::default(),
|
||||
potential_clips: FastHashMap::default(),
|
||||
id,
|
||||
}
|
||||
}
|
||||
|
|
@ -180,6 +189,7 @@ impl Tile {
|
|||
fn clear(&mut self) {
|
||||
self.transforms.clear();
|
||||
self.descriptor.clear();
|
||||
self.potential_clips.clear();
|
||||
}
|
||||
|
||||
/// Update state related to whether a tile has the same
|
||||
|
|
@ -191,9 +201,9 @@ impl Tile {
|
|||
|
||||
// The tile is only valid if:
|
||||
// - The content is the same *and*
|
||||
// - The valid part of the tile is the same wrt to world clips.
|
||||
// - The valid part of the tile includes the needed part.
|
||||
self.is_valid &= self.is_same_content;
|
||||
self.is_valid &= self.descriptor.is_valid(&tile_bounding_rect);
|
||||
self.is_valid &= self.valid_rect.contains_rect(tile_bounding_rect);
|
||||
|
||||
// Update count of how many times this tile has had the same content.
|
||||
if !self.is_same_content {
|
||||
|
|
@ -216,15 +226,6 @@ pub struct PrimitiveDescriptor {
|
|||
clip_count: u16,
|
||||
}
|
||||
|
||||
/// Defines the region of a primitive that exists on a tile.
|
||||
#[derive(Debug)]
|
||||
pub struct PrimitiveRegion {
|
||||
/// The (prim relative) portion of on this tile.
|
||||
prim_region: WorldRect,
|
||||
/// Location within the tile.
|
||||
tile_offset: WorldPoint,
|
||||
}
|
||||
|
||||
/// Uniquely describes the content of this tile, in a way that can be
|
||||
/// (reasonably) efficiently hashed and compared.
|
||||
#[derive(Debug)]
|
||||
|
|
@ -250,12 +251,6 @@ pub struct TileDescriptor {
|
|||
// TODO(gw): Ugh, get rid of all opacity binding support!
|
||||
opacity_bindings: ComparableVec<OpacityBinding>,
|
||||
|
||||
/// List of the required valid rectangles for each primitive.
|
||||
needed_regions: Vec<PrimitiveRegion>,
|
||||
|
||||
/// List of the currently valid rectangles for each primitive.
|
||||
current_regions: Vec<PrimitiveRegion>,
|
||||
|
||||
/// List of the (quantized) transforms that we care about
|
||||
/// tracking for this tile.
|
||||
transforms: ComparableVec<TransformKey>,
|
||||
|
|
@ -269,8 +264,6 @@ impl TileDescriptor {
|
|||
clip_vertices: ComparableVec::new(),
|
||||
opacity_bindings: ComparableVec::new(),
|
||||
image_keys: ComparableVec::new(),
|
||||
needed_regions: Vec::new(),
|
||||
current_regions: Vec::new(),
|
||||
transforms: ComparableVec::new(),
|
||||
}
|
||||
}
|
||||
|
|
@ -283,7 +276,6 @@ impl TileDescriptor {
|
|||
self.clip_vertices.reset();
|
||||
self.opacity_bindings.reset();
|
||||
self.image_keys.reset();
|
||||
self.needed_regions.clear();
|
||||
self.transforms.reset();
|
||||
}
|
||||
|
||||
|
|
@ -298,49 +290,6 @@ impl TileDescriptor {
|
|||
self.prims.is_valid() &&
|
||||
self.transforms.is_valid()
|
||||
}
|
||||
|
||||
/// Check if the tile is valid, given that the rest of the content is the same.
|
||||
fn is_valid(&self, tile_bounding_rect: &WorldRect) -> bool {
|
||||
// For a tile to be valid, it needs to ensure that the currently valid
|
||||
// rect of each primitive encloses the required valid rect.
|
||||
// TODO(gw): This is only needed for tiles that are partially rendered
|
||||
// (i.e. those clipped to edge of screen). We can make this much
|
||||
// faster by skipping this step for tiles that are not clipped!
|
||||
// TODO(gw): For partial tiles that *do* need this test, we can probably
|
||||
// make it faster again by caching and checking the relative
|
||||
// transforms of primitives on this tile.
|
||||
if self.needed_regions.len() == self.current_regions.len() {
|
||||
for (needed, current) in self.needed_regions.iter().zip(self.current_regions.iter()) {
|
||||
let needed_region = needed
|
||||
.prim_region
|
||||
.translate(&needed.tile_offset.to_vector())
|
||||
.intersection(tile_bounding_rect);
|
||||
|
||||
let needed_rect = match needed_region {
|
||||
Some(rect) => rect,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let current_region = current
|
||||
.prim_region
|
||||
.translate(¤t.tile_offset.to_vector())
|
||||
.intersection(tile_bounding_rect);
|
||||
|
||||
let current_rect = match current_region {
|
||||
Some(rect) => rect,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
if needed_rect != current_rect {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the dirty region of a tile cache picture.
|
||||
|
|
@ -789,6 +738,14 @@ impl TileCache {
|
|||
let mut current_clip_chain_id = prim_instance.clip_chain_id;
|
||||
let mut clip_spatial_nodes = FastHashSet::default();
|
||||
|
||||
// TODO(gw): We only care about world clip rects that don't have the main
|
||||
// scroll root as an ancestor. It may be a worthwhile optimization
|
||||
// to check for these and skip them.
|
||||
// TODO(gw): We could also trivially track and exclude the root iframe / content
|
||||
// clip chain id, since we know that will exist on every item but never
|
||||
// actually be relevant.
|
||||
let mut world_clips: FastHashMap<RectangleKey, SpatialNodeIndex> = FastHashMap::default();
|
||||
|
||||
// Some primitives can not be cached (e.g. external video images)
|
||||
let is_cacheable = prim_instance.is_cacheable(
|
||||
&resources,
|
||||
|
|
@ -885,17 +842,27 @@ impl TileCache {
|
|||
size,
|
||||
);
|
||||
|
||||
if let Some(clip_world_rect) = self.map_local_to_world.map(&local_rect) {
|
||||
// Even if this ends up getting clipped out by the current clip
|
||||
// stack, we want to ensure the primitive gets added to the tiles
|
||||
// below, to ensure invalidation isn't tripped up by the wrong
|
||||
// number of primitives that affect this tile.
|
||||
world_clip_rect = world_clip_rect
|
||||
.intersection(&clip_world_rect)
|
||||
.unwrap_or(WorldRect::zero());
|
||||
}
|
||||
match self.map_local_to_world.map(&local_rect) {
|
||||
Some(clip_world_rect) => {
|
||||
// Even if this ends up getting clipped out by the current clip
|
||||
// stack, we want to ensure the primitive gets added to the tiles
|
||||
// below, to ensure invalidation isn't tripped up by the wrong
|
||||
// number of primitives that affect this tile.
|
||||
world_clip_rect = world_clip_rect
|
||||
.intersection(&clip_world_rect)
|
||||
.unwrap_or(WorldRect::zero());
|
||||
|
||||
false
|
||||
world_clips.insert(
|
||||
clip_world_rect.into(),
|
||||
clip_chain_node.spatial_node_index,
|
||||
);
|
||||
|
||||
false
|
||||
}
|
||||
None => {
|
||||
true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
true
|
||||
}
|
||||
|
|
@ -908,9 +875,10 @@ impl TileCache {
|
|||
}
|
||||
};
|
||||
|
||||
clip_vertices.push(clip_chain_node.local_pos);
|
||||
clip_chain_uids.push(clip_chain_node.handle.uid());
|
||||
|
||||
if add_to_clip_deps {
|
||||
clip_vertices.push(clip_chain_node.local_pos);
|
||||
clip_chain_uids.push(clip_chain_node.handle.uid());
|
||||
clip_spatial_nodes.insert(clip_chain_node.spatial_node_index);
|
||||
}
|
||||
|
||||
|
|
@ -939,17 +907,6 @@ impl TileCache {
|
|||
// a partially clipped tile, which would be a significant
|
||||
// optimization for the common case (non-clipped tiles).
|
||||
|
||||
// Get the required tile-local rect that this primitive occupies.
|
||||
// Ensure that even if it's currently clipped out of this tile,
|
||||
// we still insert a rect of zero size, so that the tile descriptor's
|
||||
// needed rects array matches.
|
||||
let prim_region = world_clip_rect.translate(&-world_rect.origin.to_vector());
|
||||
|
||||
tile.descriptor.needed_regions.push(PrimitiveRegion {
|
||||
prim_region,
|
||||
tile_offset: world_rect.origin - tile.world_rect.origin.to_vector(),
|
||||
});
|
||||
|
||||
// Mark if the tile is cacheable at all.
|
||||
tile.is_same_content &= is_cacheable;
|
||||
|
||||
|
|
@ -973,6 +930,9 @@ impl TileCache {
|
|||
for spatial_node_index in &clip_spatial_nodes {
|
||||
tile.transforms.insert(*spatial_node_index);
|
||||
}
|
||||
for (world_rect, spatial_node_index) in &world_clips {
|
||||
tile.potential_clips.insert(world_rect.clone(), *spatial_node_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1018,6 +978,17 @@ impl TileCache {
|
|||
|
||||
// Step through each tile and invalidate if the dependencies have changed.
|
||||
for (i, tile) in self.tiles.iter_mut().enumerate() {
|
||||
// Deal with any potential world clips. Check to see if they are
|
||||
// outside the tile cache bounding rect. If they are, they're not
|
||||
// relevant and we don't care if they move relative to the content
|
||||
// itself. This avoids a lot of redundant invalidations.
|
||||
for (clip_world_rect, spatial_node_index) in &tile.potential_clips {
|
||||
let clip_world_rect = WorldRect::from(clip_world_rect.clone());
|
||||
if !clip_world_rect.contains_rect(&self.world_bounding_rect) {
|
||||
tile.transforms.insert(*spatial_node_index);
|
||||
}
|
||||
}
|
||||
|
||||
// Update tile transforms
|
||||
let mut transform_spatial_nodes: Vec<SpatialNodeIndex> = tile.transforms.drain().collect();
|
||||
transform_spatial_nodes.sort();
|
||||
|
|
@ -1117,6 +1088,11 @@ impl TileCache {
|
|||
let src_origin = (visible_rect.origin * frame_context.device_pixel_scale).round().to_i32();
|
||||
let valid_rect = visible_rect.translate(&-tile.world_rect.origin.to_vector());
|
||||
|
||||
tile.valid_rect = visible_rect
|
||||
.intersection(&self.world_bounding_rect)
|
||||
.map(|rect| rect.translate(&-tile.world_rect.origin.to_vector()))
|
||||
.unwrap_or(WorldRect::zero());
|
||||
|
||||
// Store a blit operation to be done after drawing the
|
||||
// frame in order to update the cached texture tile.
|
||||
let dest_rect = (valid_rect * frame_context.device_pixel_scale).round().to_i32();
|
||||
|
|
@ -1129,10 +1105,6 @@ impl TileCache {
|
|||
|
||||
// We can consider this tile valid now.
|
||||
tile.is_valid = true;
|
||||
tile.descriptor.current_regions = mem::replace(
|
||||
&mut tile.descriptor.needed_regions,
|
||||
Vec::new(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1677,7 +1649,7 @@ impl PicturePrimitive {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_visible(&self) -> bool {
|
||||
pub fn is_visible(&self) -> bool {
|
||||
match self.requested_composite_mode {
|
||||
Some(PictureCompositeMode::Filter(ref filter)) => {
|
||||
filter.is_visible()
|
||||
|
|
@ -1814,10 +1786,6 @@ impl PicturePrimitive {
|
|||
}
|
||||
};
|
||||
|
||||
if self.raster_config.as_ref().map_or(false, |c| c.establishes_raster_root) {
|
||||
frame_state.clip_store.push_raster_root(surface_spatial_node_index);
|
||||
}
|
||||
|
||||
let map_pic_to_world = SpaceMapper::new_with_target(
|
||||
ROOT_SPATIAL_NODE_INDEX,
|
||||
surface_spatial_node_index,
|
||||
|
|
@ -1902,16 +1870,9 @@ impl PicturePrimitive {
|
|||
prim_list: PrimitiveList,
|
||||
context: PictureContext,
|
||||
state: PictureState,
|
||||
frame_state: &mut FrameBuildingState,
|
||||
) -> Option<ClipNodeCollector> {
|
||||
) {
|
||||
self.prim_list = prim_list;
|
||||
self.state = Some((state, context));
|
||||
|
||||
if self.raster_config.as_ref().map_or(false, |c| c.establishes_raster_root) {
|
||||
Some(frame_state.clip_store.pop_raster_root())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn take_state_and_context(&mut self) -> (PictureState, PictureContext) {
|
||||
|
|
@ -1926,6 +1887,7 @@ impl PicturePrimitive {
|
|||
transforms: &TransformPalette,
|
||||
prim_instance: &PrimitiveInstance,
|
||||
original_local_rect: LayoutRect,
|
||||
combined_local_clip_rect: &LayoutRect,
|
||||
world_rect: WorldRect,
|
||||
plane_split_anchor: usize,
|
||||
) -> bool {
|
||||
|
|
@ -1940,7 +1902,7 @@ impl PicturePrimitive {
|
|||
// since we determine the UVs by doing a bilerp with a factor
|
||||
// from the original local rect.
|
||||
let local_rect = match original_local_rect
|
||||
.intersection(&prim_instance.combined_local_clip_rect)
|
||||
.intersection(combined_local_clip_rect)
|
||||
{
|
||||
Some(rect) => rect.cast(),
|
||||
None => return false,
|
||||
|
|
@ -2298,7 +2260,6 @@ impl PicturePrimitive {
|
|||
&mut self,
|
||||
pic_index: PictureIndex,
|
||||
prim_instance: &PrimitiveInstance,
|
||||
prim_local_rect: &LayoutRect,
|
||||
clipped_prim_bounding_rect: WorldRect,
|
||||
surface_index: SurfaceIndex,
|
||||
frame_context: &FrameBuildingContext,
|
||||
|
|
@ -2334,7 +2295,7 @@ impl PicturePrimitive {
|
|||
frame_context.clip_scroll_tree,
|
||||
);
|
||||
|
||||
let pic_rect = PictureRect::from_untyped(&prim_local_rect.to_untyped());
|
||||
let pic_rect = PictureRect::from_untyped(&self.local_rect.to_untyped());
|
||||
|
||||
let (clipped, unclipped) = match get_raster_rects(
|
||||
pic_rect,
|
||||
|
|
@ -2568,14 +2529,14 @@ impl PicturePrimitive {
|
|||
// Basic brush primitive header is (see end of prepare_prim_for_render_inner in prim_store.rs)
|
||||
// [brush specific data]
|
||||
// [segment_rect, segment data]
|
||||
let shadow_rect = prim_local_rect.translate(&offset);
|
||||
let shadow_rect = self.local_rect.translate(&offset);
|
||||
|
||||
// ImageBrush colors
|
||||
request.push(color.premultiplied());
|
||||
request.push(PremultipliedColorF::WHITE);
|
||||
request.push([
|
||||
prim_local_rect.size.width,
|
||||
prim_local_rect.size.height,
|
||||
self.local_rect.size.width,
|
||||
self.local_rect.size.height,
|
||||
0.0,
|
||||
0.0,
|
||||
]);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -3804,7 +3804,7 @@ static inline bool ArrayConstructorImpl(JSContext* cx, CallArgs& args,
|
|||
bool isConstructor) {
|
||||
RootedObject proto(cx);
|
||||
if (isConstructor) {
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Array, &proto)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -105,7 +105,8 @@ static bool Boolean(JSContext* cx, unsigned argc, Value* vp) {
|
|||
|
||||
if (args.isConstructing()) {
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Boolean,
|
||||
&proto)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ bool DataViewObject::constructSameCompartment(JSContext* cx,
|
|||
}
|
||||
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_DataView, &proto)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -186,7 +186,7 @@ bool DataViewObject::constructWrapped(JSContext* cx, HandleObject bufobj,
|
|||
// Make sure to get the [[Prototype]] for the created view from this
|
||||
// compartment.
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_DataView, &proto)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -651,7 +651,7 @@ bool MapObject::construct(JSContext* cx, unsigned argc, Value* vp) {
|
|||
}
|
||||
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Map, &proto)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1270,7 +1270,7 @@ bool SetObject::construct(JSContext* cx, unsigned argc, Value* vp) {
|
|||
}
|
||||
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Set, &proto)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2100,7 +2100,8 @@ static bool PromiseConstructor(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Promise,
|
||||
&proto)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,6 +100,9 @@ class PromiseObject : public NativeObject {
|
|||
static JSObject* unforgeableReject(JSContext* cx, HandleValue value);
|
||||
|
||||
int32_t flags() { return getFixedSlot(PromiseSlot_Flags).toInt32(); }
|
||||
void setHandled() {
|
||||
setFixedSlot(PromiseSlot_Flags, Int32Value(flags() | PROMISE_FLAG_HANDLED));
|
||||
}
|
||||
JS::PromiseState state() {
|
||||
int32_t flags = this->flags();
|
||||
if (!(flags & PROMISE_FLAG_RESOLVED)) {
|
||||
|
|
|
|||
|
|
@ -483,7 +483,7 @@ bool js::regexp_construct(JSContext* cx, unsigned argc, Value* vp) {
|
|||
|
||||
// Step 7.
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_RegExp, &proto)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -559,7 +559,7 @@ bool js::regexp_construct(JSContext* cx, unsigned argc, Value* vp) {
|
|||
|
||||
// Step 7.
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_RegExp, &proto)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -313,9 +313,8 @@ class ReadableStreamController : public StreamController {
|
|||
underlyingSource().toPrivate());
|
||||
}
|
||||
void setExternalSource(JS::ReadableStreamUnderlyingSource* underlyingSource) {
|
||||
MOZ_ASSERT(getFixedSlot(Slot_Flags).isUndefined());
|
||||
setUnderlyingSource(JS::PrivateValue(underlyingSource));
|
||||
setFlags(Flag_ExternalSource);
|
||||
addFlags(Flag_ExternalSource);
|
||||
}
|
||||
double strategyHWM() const {
|
||||
return getFixedSlot(Slot_StrategyHWM).toNumber();
|
||||
|
|
|
|||
|
|
@ -3426,7 +3426,7 @@ bool js::StringConstructor(JSContext* cx, unsigned argc, Value* vp) {
|
|||
|
||||
if (args.isConstructing()) {
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_String, &proto)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ JS_PUBLIC_API bool JS::SetWeakMapEntry(JSContext* cx, HandleObject mapObj,
|
|||
}
|
||||
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_WeakMap, &proto)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ bool WeakSetObject::construct(JSContext* cx, unsigned argc, Value* vp) {
|
|||
}
|
||||
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_WeakSet, &proto)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ static bool Collator(JSContext* cx, const CallArgs& args) {
|
|||
|
||||
// Steps 2-5 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Null, &proto)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ static bool DateTimeFormat(JSContext* cx, const CallArgs& args, bool construct,
|
|||
|
||||
// Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Null, &proto)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ static bool NumberFormat(JSContext* cx, const CallArgs& args, bool construct) {
|
|||
|
||||
// Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Null, &proto)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ static bool PluralRules(JSContext* cx, unsigned argc, Value* vp) {
|
|||
|
||||
// Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Null, &proto)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ static bool RelativeTimeFormat(JSContext* cx, unsigned argc, Value* vp) {
|
|||
|
||||
// Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Null, &proto)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -120,15 +120,14 @@ class UnwinderTypeCache(object):
|
|||
class_type = gdb.lookup_type('js::jit::' + SizeOfFramePrefix[name])
|
||||
self.frame_class_types[enumval] = class_type.pointer()
|
||||
|
||||
# gdb doesn't have a direct way to tell us if a given address is
|
||||
# claimed by some shared library or the executable. See
|
||||
# https://sourceware.org/bugzilla/show_bug.cgi?id=19288
|
||||
# In the interest of not requiring a patched gdb, instead we read
|
||||
# /proc/.../maps. This only works locally, but maybe could work
|
||||
# remotely using "remote get". FIXME.
|
||||
|
||||
|
||||
def parse_proc_maps():
|
||||
# gdb doesn't have a direct way to tell us if a given address is
|
||||
# claimed by some shared library or the executable. See
|
||||
# https://sourceware.org/bugzilla/show_bug.cgi?id=19288
|
||||
# In the interest of not requiring a patched gdb, instead we read
|
||||
# /proc/.../maps. This only works locally, but maybe could work
|
||||
# remotely using "remote get". FIXME.
|
||||
mapfile = '/proc/' + str(gdb.selected_inferior().pid) + '/maps'
|
||||
# Note we only examine executable mappings here.
|
||||
matcher = re.compile("^([a-fA-F0-9]+)-([a-fA-F0-9]+)\s+..x.\s+\S+\s+\S+\s+\S*(.*)$")
|
||||
|
|
@ -148,10 +147,10 @@ def parse_proc_maps():
|
|||
mappings.append((long(start, 16), long(end, 16)))
|
||||
return mappings
|
||||
|
||||
# A symbol/value pair as expected from gdb frame decorators.
|
||||
|
||||
|
||||
class FrameSymbol(object):
|
||||
"A symbol/value pair as expected from gdb frame decorators."
|
||||
|
||||
def __init__(self, sym, val):
|
||||
self.sym = sym
|
||||
self.val = val
|
||||
|
|
@ -162,12 +161,12 @@ class FrameSymbol(object):
|
|||
def value(self):
|
||||
return self.val
|
||||
|
||||
# This represents a single JIT frame for the purposes of display.
|
||||
# That is, the frame filter creates instances of this when it sees a
|
||||
# JIT frame in the stack.
|
||||
|
||||
|
||||
class JitFrameDecorator(FrameDecorator):
|
||||
"""This represents a single JIT frame for the purposes of display.
|
||||
That is, the frame filter creates instances of this when it sees a
|
||||
JIT frame in the stack."""
|
||||
|
||||
def __init__(self, base, info, cache):
|
||||
super(JitFrameDecorator, self).__init__(base)
|
||||
self.info = info
|
||||
|
|
@ -258,10 +257,10 @@ class JitFrameDecorator(FrameDecorator):
|
|||
result.append(FrameSymbol(name, args_ptr[i]))
|
||||
return result
|
||||
|
||||
# A frame filter for SpiderMonkey.
|
||||
|
||||
|
||||
class SpiderMonkeyFrameFilter(object):
|
||||
"A frame filter for SpiderMonkey."
|
||||
|
||||
# |state_holder| is either None, or an instance of
|
||||
# SpiderMonkeyUnwinder. If the latter, then this class will
|
||||
# reference the |unwinder_state| attribute to find the current
|
||||
|
|
@ -285,31 +284,31 @@ class SpiderMonkeyFrameFilter(object):
|
|||
def filter(self, frame_iter):
|
||||
return imap(self.maybe_wrap_frame, frame_iter)
|
||||
|
||||
# A frame id class, as specified by the gdb unwinder API.
|
||||
|
||||
|
||||
class SpiderMonkeyFrameId(object):
|
||||
"A frame id class, as specified by the gdb unwinder API."
|
||||
|
||||
def __init__(self, sp, pc):
|
||||
self.sp = sp
|
||||
self.pc = pc
|
||||
|
||||
# This holds all the state needed during a given unwind. Each time a
|
||||
# new unwind is done, a new instance of this class is created. It
|
||||
# keeps track of all the state needed to unwind JIT frames. Note that
|
||||
# this class is not directly instantiated.
|
||||
#
|
||||
# This is a base class, and must be specialized for each target
|
||||
# architecture, both because we need to use arch-specific register
|
||||
# names, and because entry frame unwinding is arch-specific.
|
||||
# See https://sourceware.org/bugzilla/show_bug.cgi?id=19286 for info
|
||||
# about the register name issue.
|
||||
#
|
||||
# Each subclass must define SP_REGISTER, PC_REGISTER, and
|
||||
# SENTINEL_REGISTER (see x64UnwinderState for info); and implement
|
||||
# unwind_entry_frame_registers.
|
||||
|
||||
|
||||
class UnwinderState(object):
|
||||
"""This holds all the state needed during a given unwind. Each time a
|
||||
new unwind is done, a new instance of this class is created. It
|
||||
keeps track of all the state needed to unwind JIT frames. Note that
|
||||
this class is not directly instantiated.
|
||||
|
||||
This is a base class, and must be specialized for each target
|
||||
architecture, both because we need to use arch-specific register
|
||||
names, and because entry frame unwinding is arch-specific.
|
||||
See https://sourceware.org/bugzilla/show_bug.cgi?id=19286 for info
|
||||
about the register name issue.
|
||||
|
||||
Each subclass must define SP_REGISTER, PC_REGISTER, and
|
||||
SENTINEL_REGISTER (see x64UnwinderState for info); and implement
|
||||
unwind_entry_frame_registers."""
|
||||
|
||||
def __init__(self, typecache):
|
||||
self.next_sp = None
|
||||
self.next_type = None
|
||||
|
|
@ -505,10 +504,10 @@ class UnwinderState(object):
|
|||
# the time being.
|
||||
return self.unwind_exit_frame(pc, pending_frame)
|
||||
|
||||
# The UnwinderState subclass for x86-64.
|
||||
|
||||
|
||||
class x64UnwinderState(UnwinderState):
|
||||
"The UnwinderState subclass for x86-64."
|
||||
|
||||
SP_REGISTER = 'rsp'
|
||||
PC_REGISTER = 'rip'
|
||||
|
||||
|
|
@ -534,12 +533,12 @@ class x64UnwinderState(UnwinderState):
|
|||
if reg is "rbp":
|
||||
unwind_info.add_saved_register(self.SP_REGISTER, sp)
|
||||
|
||||
# The unwinder object. This provides the "user interface" to the JIT
|
||||
# unwinder, and also handles constructing or destroying UnwinderState
|
||||
# objects as needed.
|
||||
|
||||
|
||||
class SpiderMonkeyUnwinder(Unwinder):
|
||||
"""The unwinder object. This provides the "user interface" to the JIT
|
||||
unwinder, and also handles constructing or destroying UnwinderState
|
||||
objects as needed."""
|
||||
|
||||
# A list of all the possible unwinders. See |self.make_unwinder|.
|
||||
UNWINDERS = [x64UnwinderState]
|
||||
|
||||
|
|
@ -601,11 +600,11 @@ class SpiderMonkeyUnwinder(Unwinder):
|
|||
def invalidate_unwinder_state(self, *args, **kwargs):
|
||||
self.unwinder_state = None
|
||||
|
||||
# Register the unwinder and frame filter with |objfile|. If |objfile|
|
||||
# is None, register them globally.
|
||||
|
||||
|
||||
def register_unwinder(objfile):
|
||||
"""Register the unwinder and frame filter with |objfile|. If |objfile|
|
||||
is None, register them globally."""
|
||||
|
||||
type_cache = UnwinderTypeCache()
|
||||
unwinder = None
|
||||
# This currently only works on Linux, due to parse_proc_maps.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
// Releasing a reader should not result in a promise being tracked as
|
||||
// unhandled.
|
||||
|
||||
function test(readable) {
|
||||
// Create an errored stream.
|
||||
let controller;
|
||||
let stream = new ReadableStream({
|
||||
start(c) {
|
||||
controller = c;
|
||||
}
|
||||
});
|
||||
drainJobQueue();
|
||||
|
||||
// Track promises.
|
||||
let status = new Map;
|
||||
setPromiseRejectionTrackerCallback((p, x) => { status.set(p, x); });
|
||||
|
||||
// Per Streams spec 3.7.5 step 5, this creates a rejected promise
|
||||
// (reader.closed) but marks it as handled.
|
||||
let reader = stream.getReader();
|
||||
if (!readable) {
|
||||
controller.close();
|
||||
}
|
||||
reader.releaseLock();
|
||||
|
||||
// Check that the promise's status is not 0 (unhandled);
|
||||
// it may be either 1 (handled) or undefined (never tracked).
|
||||
let result = status.get(reader.closed);
|
||||
assertEq(result === 1 || result === undefined, true);
|
||||
}
|
||||
|
||||
test(true);
|
||||
test(false);
|
||||
23
js/src/jit-test/tests/stream/reader-closedPromise-handled.js
Normal file
23
js/src/jit-test/tests/stream/reader-closedPromise-handled.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
// Creating a reader from an errored stream should not result in a promise
|
||||
// being tracked as unhandled.
|
||||
|
||||
// Create an errored stream.
|
||||
let stream = new ReadableStream({
|
||||
start(controller) {
|
||||
controller.error(new Error("splines insufficiently reticulated"));
|
||||
}
|
||||
});
|
||||
drainJobQueue();
|
||||
|
||||
// Track promises.
|
||||
let status = new Map;
|
||||
setPromiseRejectionTrackerCallback((p, x) => { status.set(p, x); });
|
||||
|
||||
// Per Streams spec 3.7.4 step 5.c, this creates a rejected promise
|
||||
// (reader.closed) but marks it as handled.
|
||||
let reader = stream.getReader();
|
||||
|
||||
// Check that the promise's status is not 0 (unhandled);
|
||||
// it may be either 1 (handled) or undefined (never tracked).
|
||||
let result = status.get(reader.closed);
|
||||
assertEq(result === 1 || result === undefined, true);
|
||||
|
|
@ -3136,7 +3136,7 @@ static bool NewDateObject(JSContext* cx, const CallArgs& args, ClippedTime t) {
|
|||
MOZ_ASSERT(args.isConstructing());
|
||||
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Date, &proto)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -388,13 +388,23 @@ JS_PUBLIC_API uint64_t JS::ExceptionTimeWarpTarget(JS::HandleValue value) {
|
|||
bool Error(JSContext* cx, unsigned argc, Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
// ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when
|
||||
// called as functions, without operator new. But as we do not give
|
||||
// each constructor a distinct JSClass, we must get the exception type
|
||||
// ourselves.
|
||||
JSExnType exnType =
|
||||
JSExnType(args.callee().as<JSFunction>().getExtendedSlot(0).toInt32());
|
||||
|
||||
JSProtoKey protoKey =
|
||||
JSCLASS_CACHED_PROTO_KEY(&ErrorObject::classes[exnType]);
|
||||
|
||||
// ES6 19.5.1.1 mandates the .prototype lookup happens before the toString
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, protoKey, &proto)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Compute the error message, if any. */
|
||||
// Compute the error message, if any.
|
||||
RootedString message(cx, nullptr);
|
||||
if (args.hasDefined(0)) {
|
||||
message = ToString<CanGC>(cx, args[0]);
|
||||
|
|
@ -403,10 +413,9 @@ bool Error(JSContext* cx, unsigned argc, Value* vp) {
|
|||
}
|
||||
}
|
||||
|
||||
/* Find the scripted caller, but only ones we're allowed to know about. */
|
||||
// Find the scripted caller, but only ones we're allowed to know about.
|
||||
NonBuiltinFrameIter iter(cx, cx->realm()->principals());
|
||||
|
||||
/* Set the 'fileName' property. */
|
||||
RootedString fileName(cx);
|
||||
if (args.length() > 1) {
|
||||
fileName = ToString<CanGC>(cx, args[1]);
|
||||
|
|
@ -422,7 +431,6 @@ bool Error(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Set the 'lineNumber' property. */
|
||||
uint32_t lineNumber, columnNumber = 0;
|
||||
if (args.length() > 2) {
|
||||
if (!ToUint32(cx, args[2], &lineNumber)) {
|
||||
|
|
@ -438,15 +446,6 @@ bool Error(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when
|
||||
* called as functions, without operator new. But as we do not give
|
||||
* each constructor a distinct JSClass, we must get the exception type
|
||||
* ourselves.
|
||||
*/
|
||||
JSExnType exnType =
|
||||
JSExnType(args.callee().as<JSFunction>().getExtendedSlot(0).toInt32());
|
||||
|
||||
RootedObject obj(cx,
|
||||
ErrorObject::create(cx, exnType, stack, fileName, lineNumber,
|
||||
columnNumber, nullptr, message, proto));
|
||||
|
|
|
|||
|
|
@ -563,7 +563,7 @@ static bool Number(JSContext* cx, unsigned argc, Value* vp) {
|
|||
}
|
||||
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Number, &proto)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -266,12 +266,12 @@ skip script test262/built-ins/Promise/resolve-function-name.js
|
|||
# https://bugzilla.mozilla.org/show_bug.cgi?id=944846
|
||||
skip script test262/built-ins/Number/prototype/toExponential/return-values.js
|
||||
|
||||
# https://bugzilla.mozilla.org/show_bug.cgi?id=1288457
|
||||
skip script test262/built-ins/Function/internals/Construct/base-ctor-revoked-proxy-realm.js
|
||||
|
||||
# https://bugzilla.mozilla.org/show_bug.cgi?id=1225839
|
||||
skip script test262/built-ins/Function/internals/Call/class-ctor-realm.js
|
||||
|
||||
# https://bugzilla.mozilla.org/show_bug.cgi?id=1288457
|
||||
skip script test262/built-ins/Function/internals/Construct/base-ctor-revoked-proxy-realm.js
|
||||
|
||||
# https://bugzilla.mozilla.org/show_bug.cgi?id=1297179
|
||||
skip script test262/built-ins/Proxy/apply/arguments-realm.js
|
||||
skip script test262/built-ins/Proxy/apply/trap-is-not-callable-realm.js
|
||||
|
|
@ -298,51 +298,15 @@ skip script test262/built-ins/Proxy/preventExtensions/trap-is-not-callable-realm
|
|||
skip script test262/built-ins/Proxy/set/trap-is-not-callable-realm.js
|
||||
skip script test262/built-ins/Proxy/setPrototypeOf/trap-is-not-callable-realm.js
|
||||
|
||||
# Erros thrown from wrong realm, similar to 1225839, 1288457, and 1297179.
|
||||
# Errors thrown from wrong realm, similar to 1225839, 1288457, and 1297179.
|
||||
skip script test262/built-ins/Array/length/define-own-prop-length-overflow-realm.js
|
||||
skip script test262/built-ins/Function/internals/Construct/derived-return-val-realm.js
|
||||
skip script test262/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js
|
||||
|
||||
# https://bugzilla.mozilla.org/show_bug.cgi?id=1317416
|
||||
skip script test262/language/expressions/super/realm.js
|
||||
skip script test262/built-ins/Array/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/ArrayBuffer/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/Boolean/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/DataView/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/DataView/proto-from-ctor-realm-sab.js
|
||||
skip script test262/built-ins/Date/proto-from-ctor-realm-one.js
|
||||
skip script test262/built-ins/Date/proto-from-ctor-realm-two.js
|
||||
skip script test262/built-ins/Date/proto-from-ctor-realm-zero.js
|
||||
skip script test262/built-ins/Error/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/Function/prototype/bind/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/Function/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/GeneratorFunction/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/Map/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/Number/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/Object/proto-from-ctor.js
|
||||
skip script test262/built-ins/Promise/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/RegExp/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/Set/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/SharedArrayBuffer/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/String/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/TypedArrayConstructors/ctors-bigint/buffer-arg/proto-from-ctor-realm-sab.js
|
||||
skip script test262/built-ins/TypedArrayConstructors/ctors-bigint/length-arg/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/TypedArrayConstructors/ctors-bigint/no-args/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/TypedArrayConstructors/ctors-bigint/object-arg/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/other-ctor-buffer-ctor-custom-species-proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/TypedArrayConstructors/ctors-bigint/typedarray-arg/same-ctor-buffer-ctor-species-custom-proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/TypedArrayConstructors/ctors/buffer-arg/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/TypedArrayConstructors/ctors/buffer-arg/proto-from-ctor-realm-sab.js
|
||||
skip script test262/built-ins/TypedArrayConstructors/ctors/length-arg/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/TypedArrayConstructors/ctors/no-args/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/TypedArrayConstructors/ctors/object-arg/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/TypedArrayConstructors/ctors/typedarray-arg/other-ctor-buffer-ctor-custom-species-proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/TypedArrayConstructors/ctors/typedarray-arg/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/TypedArrayConstructors/ctors/typedarray-arg/same-ctor-buffer-ctor-species-custom-proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/WeakMap/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/WeakSet/proto-from-ctor-realm.js
|
||||
skip script test262/built-ins/Function/prototype/bind/proto-from-ctor-realm.js
|
||||
|
||||
# https://bugzilla.mozilla.org/show_bug.cgi?id=1317395
|
||||
skip script test262/built-ins/ArrayBuffer/prototype/byteLength/detached-buffer.js
|
||||
|
|
|
|||
|
|
@ -155,6 +155,12 @@ def parse_args():
|
|||
help='Get tests from the given file.')
|
||||
input_og.add_option('-x', '--exclude-file', action='append',
|
||||
help='Exclude tests from the given file.')
|
||||
input_og.add_option('--wpt', dest='wpt',
|
||||
type='choice',
|
||||
choices=['enabled', 'disabled', 'if-running-everything'],
|
||||
default='if-running-everything',
|
||||
help="Enable or disable shell web-platform-tests "
|
||||
"(default: enable if no test paths are specified).")
|
||||
input_og.add_option('--include', action='append', dest='requested_paths', default=[],
|
||||
help='Include the given test file or directory.')
|
||||
input_og.add_option('--exclude', action='append', dest='excluded_paths', default=[],
|
||||
|
|
@ -434,7 +440,11 @@ def load_tests(options, requested_paths, excluded_paths):
|
|||
test_gen = manifest.load_reftests(test_dir, path_options, xul_tester)
|
||||
|
||||
# WPT tests are already run in the browser in their own harness.
|
||||
if not options.make_manifests:
|
||||
wpt_enabled = (options.wpt == 'enabled' or
|
||||
(options.wpt == 'if-running-everything' and
|
||||
len(requested_paths) == 0 and
|
||||
not options.make_manifests))
|
||||
if wpt_enabled:
|
||||
wpt_tests = load_wpt_tests(xul_tester,
|
||||
requested_paths,
|
||||
excluded_paths)
|
||||
|
|
|
|||
|
|
@ -419,7 +419,8 @@ bool ArrayBufferObject::class_constructor(JSContext* cx, unsigned argc,
|
|||
// Step 3 (Inlined 24.1.1.1 AllocateArrayBuffer).
|
||||
// 24.1.1.1, step 1 (Inlined 9.1.14 OrdinaryCreateFromConstructor).
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_ArrayBuffer,
|
||||
&proto)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -121,12 +121,12 @@ class GlobalObject : public NativeObject {
|
|||
"global object slot counts are inconsistent");
|
||||
|
||||
static unsigned constructorSlot(JSProtoKey key) {
|
||||
MOZ_ASSERT(key <= JSProto_LIMIT);
|
||||
MOZ_ASSERT(key < JSProto_LIMIT);
|
||||
return APPLICATION_SLOTS + key;
|
||||
}
|
||||
|
||||
static unsigned prototypeSlot(JSProtoKey key) {
|
||||
MOZ_ASSERT(key <= JSProto_LIMIT);
|
||||
MOZ_ASSERT(key < JSProto_LIMIT);
|
||||
return APPLICATION_SLOTS + JSProto_LIMIT + key;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -357,7 +357,7 @@ class MOZ_STACK_CLASS TryNoteIter {
|
|||
} while (!(pcInRange() && tn_->kind == JSTRY_FOR_OF));
|
||||
|
||||
// Advance to trynote following the enclosing for-of.
|
||||
++tn_;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -1999,6 +1999,7 @@ static bool CreateDynamicFunction(JSContext* cx, const CallArgs& args,
|
|||
return false;
|
||||
}
|
||||
|
||||
JSProtoKey protoKey = JSProto_Null;
|
||||
if (isAsync) {
|
||||
if (isGenerator) {
|
||||
if (!CompileStandaloneAsyncGenerator(cx, &fun, options, srcBuf,
|
||||
|
|
@ -2022,12 +2023,13 @@ static bool CreateDynamicFunction(JSContext* cx, const CallArgs& args,
|
|||
parameterListEnd)) {
|
||||
return false;
|
||||
}
|
||||
protoKey = JSProto_Function;
|
||||
}
|
||||
}
|
||||
|
||||
// Steps 6, 29.
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, protoKey, &proto)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1026,7 +1026,8 @@ bool js::NewObjectScriptedCall(JSContext* cx, MutableHandleObject pobj) {
|
|||
JSObject* js::CreateThis(JSContext* cx, const Class* newclasp,
|
||||
HandleObject callee) {
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromConstructor(cx, callee, &proto)) {
|
||||
if (!GetPrototypeFromConstructor(
|
||||
cx, callee, JSCLASS_CACHED_PROTO_KEY(newclasp), &proto)) {
|
||||
return nullptr;
|
||||
}
|
||||
gc::AllocKind kind = NewObjectGCKind(newclasp);
|
||||
|
|
@ -1158,12 +1159,45 @@ JSObject* js::CreateThisForFunctionWithProto(
|
|||
}
|
||||
|
||||
bool js::GetPrototypeFromConstructor(JSContext* cx, HandleObject newTarget,
|
||||
JSProtoKey intrinsicDefaultProto,
|
||||
MutableHandleObject proto) {
|
||||
RootedValue protov(cx);
|
||||
if (!GetProperty(cx, newTarget, newTarget, cx->names().prototype, &protov)) {
|
||||
return false;
|
||||
}
|
||||
proto.set(protov.isObject() ? &protov.toObject() : nullptr);
|
||||
if (protov.isObject()) {
|
||||
proto.set(&protov.toObject());
|
||||
} else if (newTarget->is<JSFunction>() &&
|
||||
newTarget->as<JSFunction>().realm() == cx->realm()) {
|
||||
// Steps 4.a-b fetch the builtin prototype of the current realm, which we
|
||||
// represent as nullptr.
|
||||
proto.set(nullptr);
|
||||
} else if (intrinsicDefaultProto == JSProto_Null) {
|
||||
// Bug 1317416. The caller did not pass a reasonable JSProtoKey, so let the
|
||||
// caller select a prototype object. Most likely they will choose one from
|
||||
// the wrong realm.
|
||||
proto.set(nullptr);
|
||||
} else {
|
||||
// Step 4.a: Let realm be ? GetFunctionRealm(constructor);
|
||||
JSObject* unwrappedConstructor = CheckedUnwrap(newTarget);
|
||||
if (!unwrappedConstructor) {
|
||||
ReportAccessDenied(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 4.b: Set proto to realm's intrinsic object named
|
||||
// intrinsicDefaultProto.
|
||||
{
|
||||
AutoRealm ar(cx, unwrappedConstructor);
|
||||
proto.set(GlobalObject::getOrCreatePrototype(cx, intrinsicDefaultProto));
|
||||
}
|
||||
if (!proto) {
|
||||
return false;
|
||||
}
|
||||
if (!cx->compartment()->wrap(cx, proto)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1171,7 +1205,7 @@ JSObject* js::CreateThisForFunction(JSContext* cx, HandleObject callee,
|
|||
HandleObject newTarget,
|
||||
NewObjectKind newKind) {
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) {
|
||||
if (!GetPrototypeFromConstructor(cx, newTarget, JSProto_Null, &proto)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -3679,6 +3713,10 @@ static void DumpProperty(const NativeObject* obj, Shape& shape,
|
|||
out.printf(")\n");
|
||||
}
|
||||
|
||||
bool JSObject::hasSameRealmAs(JSContext* cx) const {
|
||||
return nonCCWRealm() == cx->realm();
|
||||
}
|
||||
|
||||
bool JSObject::uninlinedIsProxy() const { return is<ProxyObject>(); }
|
||||
|
||||
bool JSObject::uninlinedNonProxyIsExtensible() const {
|
||||
|
|
|
|||
|
|
@ -435,6 +435,7 @@ class JSObject : public js::gc::Cell {
|
|||
MOZ_ASSERT(!js::UninlinedIsCrossCompartmentWrapper(this));
|
||||
return group_->realm();
|
||||
}
|
||||
bool hasSameRealmAs(JSContext* cx) const;
|
||||
|
||||
// Returns the object's realm even if the object is a CCW (be careful, in
|
||||
// this case the realm is not very meaningful because wrappers are shared by
|
||||
|
|
@ -793,14 +794,35 @@ bool NewObjectWithTaggedProtoIsCachable(JSContext* cx,
|
|||
// ES6 9.1.15 GetPrototypeFromConstructor.
|
||||
extern bool GetPrototypeFromConstructor(JSContext* cx,
|
||||
js::HandleObject newTarget,
|
||||
JSProtoKey intrinsicDefaultProto,
|
||||
js::MutableHandleObject proto);
|
||||
|
||||
// https://tc39.github.io/ecma262/#sec-getprototypefromconstructor
|
||||
//
|
||||
// Determine which [[Prototype]] to use when creating a new object using a
|
||||
// builtin constructor.
|
||||
//
|
||||
// This sets `proto` to `nullptr` to mean "the builtin prototype object for
|
||||
// this type in the current realm", the common case.
|
||||
//
|
||||
// We could set it to `cx->global()->getOrCreatePrototype(protoKey)`, but
|
||||
// nullptr gets a fast path in e.g. js::NewObjectWithClassProtoCommon.
|
||||
//
|
||||
// intrinsicDefaultProto can be JSProto_Null if there's no appropriate
|
||||
// JSProtoKey enum; but we then select the wrong prototype object in a
|
||||
// multi-realm corner case (see bug 1515167).
|
||||
MOZ_ALWAYS_INLINE bool GetPrototypeFromBuiltinConstructor(
|
||||
JSContext* cx, const CallArgs& args, js::MutableHandleObject proto) {
|
||||
// When proto is set to nullptr, the caller is expected to select the
|
||||
// correct default built-in prototype for this constructor.
|
||||
JSContext* cx, const CallArgs& args, JSProtoKey intrinsicDefaultProto,
|
||||
js::MutableHandleObject proto) {
|
||||
// We can skip the "prototype" lookup in the two common cases:
|
||||
// 1. Builtin constructor called without `new`, as in `obj = Object();`.
|
||||
// 2. Builtin constructor called with `new`, as in `obj = new Object();`.
|
||||
//
|
||||
// Cases that can't take the fast path include `new MySubclassOfObject()`,
|
||||
// `new otherGlobal.Object()`, and `Reflect.construct(Object, [], Date)`.
|
||||
if (!args.isConstructing() ||
|
||||
&args.newTarget().toObject() == &args.callee()) {
|
||||
MOZ_ASSERT(args.callee().hasSameRealmAs(cx));
|
||||
proto.set(nullptr);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -808,7 +830,8 @@ MOZ_ALWAYS_INLINE bool GetPrototypeFromBuiltinConstructor(
|
|||
// We're calling this constructor from a derived class, retrieve the
|
||||
// actual prototype from newTarget.
|
||||
RootedObject newTarget(cx, &args.newTarget().toObject());
|
||||
return GetPrototypeFromConstructor(cx, newTarget, proto);
|
||||
return GetPrototypeFromConstructor(cx, newTarget, intrinsicDefaultProto,
|
||||
proto);
|
||||
}
|
||||
|
||||
// Specialized call for constructing |this| with a known function callee,
|
||||
|
|
|
|||
|
|
@ -198,7 +198,8 @@ bool SharedArrayBufferObject::class_constructor(JSContext* cx, unsigned argc,
|
|||
// Step 3 (Inlined 24.2.1.1 AllocateSharedArrayBuffer).
|
||||
// 24.2.1.1, step 1 (Inlined 9.1.14 OrdinaryCreateFromConstructor).
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_SharedArrayBuffer,
|
||||
&proto)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -121,38 +121,47 @@ struct TypeIDOfType;
|
|||
template <>
|
||||
struct TypeIDOfType<int8_t> {
|
||||
static const Scalar::Type id = Scalar::Int8;
|
||||
static const JSProtoKey protoKey = JSProto_Int8Array;
|
||||
};
|
||||
template <>
|
||||
struct TypeIDOfType<uint8_t> {
|
||||
static const Scalar::Type id = Scalar::Uint8;
|
||||
static const JSProtoKey protoKey = JSProto_Uint8Array;
|
||||
};
|
||||
template <>
|
||||
struct TypeIDOfType<int16_t> {
|
||||
static const Scalar::Type id = Scalar::Int16;
|
||||
static const JSProtoKey protoKey = JSProto_Int16Array;
|
||||
};
|
||||
template <>
|
||||
struct TypeIDOfType<uint16_t> {
|
||||
static const Scalar::Type id = Scalar::Uint16;
|
||||
static const JSProtoKey protoKey = JSProto_Uint16Array;
|
||||
};
|
||||
template <>
|
||||
struct TypeIDOfType<int32_t> {
|
||||
static const Scalar::Type id = Scalar::Int32;
|
||||
static const JSProtoKey protoKey = JSProto_Int32Array;
|
||||
};
|
||||
template <>
|
||||
struct TypeIDOfType<uint32_t> {
|
||||
static const Scalar::Type id = Scalar::Uint32;
|
||||
static const JSProtoKey protoKey = JSProto_Uint32Array;
|
||||
};
|
||||
template <>
|
||||
struct TypeIDOfType<float> {
|
||||
static const Scalar::Type id = Scalar::Float32;
|
||||
static const JSProtoKey protoKey = JSProto_Float32Array;
|
||||
};
|
||||
template <>
|
||||
struct TypeIDOfType<double> {
|
||||
static const Scalar::Type id = Scalar::Float64;
|
||||
static const JSProtoKey protoKey = JSProto_Float64Array;
|
||||
};
|
||||
template <>
|
||||
struct TypeIDOfType<uint8_clamped> {
|
||||
static const Scalar::Type id = Scalar::Uint8Clamped;
|
||||
static const JSProtoKey protoKey = JSProto_Uint8ClampedArray;
|
||||
};
|
||||
|
||||
class SharedOps {
|
||||
|
|
|
|||
|
|
@ -285,6 +285,10 @@ class TypedArrayObjectTemplate : public TypedArrayObject {
|
|||
static constexpr Scalar::Type ArrayTypeID() {
|
||||
return TypeIDOfType<NativeType>::id;
|
||||
}
|
||||
static constexpr JSProtoKey protoKey() {
|
||||
return TypeIDOfType<NativeType>::protoKey;
|
||||
}
|
||||
|
||||
static constexpr bool ArrayTypeIsUnsigned() {
|
||||
return TypeIsUnsigned<NativeType>();
|
||||
}
|
||||
|
|
@ -596,7 +600,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject {
|
|||
// 22.2.4.1, step 3 and 22.2.4.2, step 5.
|
||||
// 22.2.4.2.1 AllocateTypedArray, step 1.
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, protoKey(), &proto)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -608,7 +612,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject {
|
|||
// 22.2.4.{3,4,5}, step 4.
|
||||
// 22.2.4.2.1 AllocateTypedArray, step 1.
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, protoKey(), &proto)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -957,20 +961,9 @@ template <typename T>
|
|||
// As an optimization, skip the "prototype" lookup for %ArrayBuffer%.
|
||||
if (ctor != arrayBufferCtor) {
|
||||
// 9.1.13 OrdinaryCreateFromConstructor, steps 1-2.
|
||||
if (!GetPrototypeFromConstructor(cx, ctor, &proto)) {
|
||||
if (!GetPrototypeFromConstructor(cx, ctor, JSProto_ArrayBuffer, &proto)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JSObject* arrayBufferProto =
|
||||
GlobalObject::getOrCreateArrayBufferPrototype(cx, cx->global());
|
||||
if (!arrayBufferProto) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reset |proto| if it's the default %ArrayBufferPrototype%.
|
||||
if (proto == arrayBufferProto) {
|
||||
proto = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// 24.1.1.1 steps 1 (remaining part), 2-6.
|
||||
|
|
|
|||
|
|
@ -2557,7 +2557,6 @@ static void WrapSeparatorTransform(nsDisplayListBuilder* aBuilder,
|
|||
nsDisplayTransform* item = MakeDisplayItem<nsDisplayTransform>(
|
||||
aBuilder, aFrame, aNonParticipants, aBuilder->GetVisibleRect(),
|
||||
Matrix4x4(), aIndex);
|
||||
item->SetNoExtendContext();
|
||||
|
||||
if (*aSeparator == nullptr) {
|
||||
*aSeparator = item;
|
||||
|
|
|
|||
|
|
@ -7184,7 +7184,6 @@ nsDisplayTransform::nsDisplayTransform(
|
|||
mAnimatedGeometryRootForScrollMetadata(mAnimatedGeometryRoot),
|
||||
mChildrenBuildingRect(aChildrenBuildingRect),
|
||||
mIndex(aIndex),
|
||||
mNoExtendContext(false),
|
||||
mIsTransformSeparator(false),
|
||||
mTransformPreserves3DInited(false),
|
||||
mAllowAsyncAnimation(false) {
|
||||
|
|
@ -7248,7 +7247,6 @@ nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
|
|||
mAnimatedGeometryRootForScrollMetadata(mAnimatedGeometryRoot),
|
||||
mChildrenBuildingRect(aChildrenBuildingRect),
|
||||
mIndex(aIndex),
|
||||
mNoExtendContext(false),
|
||||
mIsTransformSeparator(false),
|
||||
mTransformPreserves3DInited(false),
|
||||
mAllowAsyncAnimation(aAllowAsyncAnimation) {
|
||||
|
|
@ -7272,7 +7270,6 @@ nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
|
|||
mAnimatedGeometryRootForScrollMetadata(mAnimatedGeometryRoot),
|
||||
mChildrenBuildingRect(aChildrenBuildingRect),
|
||||
mIndex(aIndex),
|
||||
mNoExtendContext(false),
|
||||
mIsTransformSeparator(true),
|
||||
mTransformPreserves3DInited(false),
|
||||
mAllowAsyncAnimation(false) {
|
||||
|
|
@ -7873,13 +7870,15 @@ bool nsDisplayTransform::CreateWebRenderCommands(
|
|||
bool animated =
|
||||
ActiveLayerTracker::IsStyleMaybeAnimated(Frame(), eCSSProperty_transform);
|
||||
|
||||
bool preserve3D = mFrame->Extend3DContext() && !mIsTransformSeparator;
|
||||
|
||||
StackingContextHelper sc(
|
||||
aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder, filters,
|
||||
LayoutDeviceRect(position, LayoutDeviceSize()), &newTransformMatrix,
|
||||
animationsId ? &prop : nullptr, nullptr, transformForSC, nullptr,
|
||||
gfx::CompositionOp::OP_OVER, !BackfaceIsHidden(),
|
||||
mFrame->Extend3DContext() && !mNoExtendContext, deferredTransformItem,
|
||||
wr::WrStackingContextClip::None(), animated);
|
||||
preserve3D, deferredTransformItem, wr::WrStackingContextClip::None(),
|
||||
animated);
|
||||
|
||||
return mStoredList.CreateWebRenderCommands(aBuilder, aResources, sc, aManager,
|
||||
aDisplayListBuilder);
|
||||
|
|
@ -7932,8 +7931,8 @@ already_AddRefed<Layer> nsDisplayTransform::BuildLayer(
|
|||
}
|
||||
|
||||
// Add the preserve-3d flag for this layer, BuildContainerLayerFor clears all
|
||||
// flags, so we never need to explicitely unset this flag.
|
||||
if (mFrame->Extend3DContext() && !mNoExtendContext) {
|
||||
// flags, so we never need to explicitly unset this flag.
|
||||
if (mFrame->Extend3DContext() && !mIsTransformSeparator) {
|
||||
container->SetContentFlags(container->GetContentFlags() |
|
||||
Layer::CONTENT_EXTEND_3D_CONTEXT);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -6710,10 +6710,6 @@ class nsDisplayTransform : public nsDisplayHitTestInfoItem {
|
|||
|
||||
void WriteDebugInfo(std::stringstream& aStream) override;
|
||||
|
||||
// Force the layer created for this item not to extend 3D context.
|
||||
// See nsIFrame::BuildDisplayListForStackingContext()
|
||||
void SetNoExtendContext() { mNoExtendContext = true; }
|
||||
|
||||
void DoUpdateBoundsPreserves3D(nsDisplayListBuilder* aBuilder) override {
|
||||
MOZ_ASSERT(mFrame->Combines3DTransformWithAncestors() ||
|
||||
IsTransformSeparator());
|
||||
|
|
@ -6794,15 +6790,13 @@ class nsDisplayTransform : public nsDisplayHitTestInfoItem {
|
|||
mutable nsRect mBounds;
|
||||
// True for mBounds is valid.
|
||||
mutable bool mHasBounds;
|
||||
// Be forced not to extend 3D context. Since we don't create a
|
||||
// transform item, a container layer, for every frames in a
|
||||
// preserves3d context, the transform items of a child preserves3d
|
||||
// context may extend the parent context not intented if the root of
|
||||
// the child preserves3d context doesn't create a transform item.
|
||||
// With this flags, we force the item not extending 3D context.
|
||||
bool mNoExtendContext;
|
||||
// This item is a separator between 3D rendering contexts, and
|
||||
// mTransform have been presetted by the constructor.
|
||||
// This also forces us not to extend the 3D context. Since we don't create a
|
||||
// transform item, a container layer, for every frame in a preserves3d
|
||||
// context, the transform items of a child preserves3d context may extend the
|
||||
// parent context unintendedly if the root of the child preserves3d context
|
||||
// doesn't create a transform item.
|
||||
bool mIsTransformSeparator;
|
||||
// True if mTransformPreserves3D have been initialized.
|
||||
bool mTransformPreserves3DInited;
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ import android.net.Uri;
|
|||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Parcelable;
|
||||
import android.os.StrictMode;
|
||||
import android.provider.ContactsContract;
|
||||
import android.support.annotation.NonNull;
|
||||
|
|
@ -71,6 +72,7 @@ import android.support.design.widget.Snackbar;
|
|||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.util.SparseIntArray;
|
||||
import android.view.KeyEvent;
|
||||
|
|
@ -136,6 +138,7 @@ public abstract class GeckoApp extends GeckoActivity
|
|||
|
||||
public static final String INTENT_REGISTER_STUMBLER_LISTENER = "org.mozilla.gecko.STUMBLER_REGISTER_LOCAL_LISTENER";
|
||||
|
||||
private static final String GECKOVIEW_STATE_BUNDLE = "geckoViewState";
|
||||
public static final String EXTRA_STATE_BUNDLE = "stateBundle";
|
||||
|
||||
public static final String PREFS_ALLOW_STATE_BUNDLE = "allowStateBundle";
|
||||
|
|
@ -658,6 +661,16 @@ public abstract class GeckoApp extends GeckoActivity
|
|||
}
|
||||
|
||||
outState.putBoolean(SAVED_STATE_IN_BACKGROUND, isApplicationInBackground());
|
||||
|
||||
// There are situations where the saved instance state will be cleared (e.g. user swipes
|
||||
// away activity in the task switcher), but Gecko will actually remain alive (because
|
||||
// another activity or service of ours is still running in this process). The saved state is
|
||||
// the only way we can reconnect to our previous GeckoView session and all the user's open
|
||||
// tabs, so we need to keep a copy of the state ourselves.
|
||||
SparseArray<Parcelable> geckoViewState = new SparseArray<>();
|
||||
mLayerView.saveHierarchyState(geckoViewState);
|
||||
outState.putSparseParcelableArray(GECKOVIEW_STATE_BUNDLE, geckoViewState);
|
||||
getGeckoApplication().setSavedState(geckoViewState);
|
||||
}
|
||||
|
||||
public void addTab(int flags) { }
|
||||
|
|
@ -696,7 +709,7 @@ public abstract class GeckoApp extends GeckoActivity
|
|||
rec.recordGeckoStartupTime(mGeckoReadyStartupTimer.getElapsed());
|
||||
}
|
||||
|
||||
((GeckoApplication) getApplicationContext()).onDelayedStartup();
|
||||
getGeckoApplication().onDelayedStartup();
|
||||
|
||||
// Reset the crash loop counter if we remain alive for at least half a minute.
|
||||
ThreadUtils.postDelayedToBackgroundThread(new Runnable() {
|
||||
|
|
@ -976,6 +989,11 @@ public abstract class GeckoApp extends GeckoActivity
|
|||
**/
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
// Within onCreate(), we might inject a different savedInstanceState for testing, but this
|
||||
// won't influence what the OS will do with regards to calling onSaveInstanceState().
|
||||
// Therefore, record whether we were passed some data or not.
|
||||
final boolean receivedSavedInstanceState = (savedInstanceState != null);
|
||||
|
||||
// Enable Android Strict Mode for developers' local builds (the "default" channel).
|
||||
if ("default".equals(AppConstants.MOZ_UPDATE_CHANNEL)) {
|
||||
enableStrictMode();
|
||||
|
|
@ -1106,6 +1124,9 @@ public abstract class GeckoApp extends GeckoActivity
|
|||
mGeckoLayout = (RelativeLayout) findViewById(R.id.gecko_layout);
|
||||
mMainLayout = (RelativeLayout) findViewById(R.id.main_layout);
|
||||
mLayerView = (GeckoView) findViewById(R.id.layer_view);
|
||||
// Disable automatic state staving - we require some special handling that we need to do
|
||||
// ourselves.
|
||||
mLayerView.setSaveFromParentEnabled(false);
|
||||
|
||||
final GeckoSession session = new GeckoSession(
|
||||
new GeckoSessionSettings.Builder()
|
||||
|
|
@ -1119,6 +1140,9 @@ public abstract class GeckoApp extends GeckoActivity
|
|||
}
|
||||
mLayerView.setSession(session, GeckoApplication.getRuntime());
|
||||
mLayerView.setOverScrollMode(View.OVER_SCROLL_NEVER);
|
||||
if (mIsRestoringActivity && !receivedSavedInstanceState) {
|
||||
restoreGeckoViewState(getGeckoApplication().getSavedState());
|
||||
}
|
||||
|
||||
getAppEventDispatcher().registerGeckoThreadListener(this,
|
||||
"Locale:Set",
|
||||
|
|
@ -1313,6 +1337,26 @@ public abstract class GeckoApp extends GeckoActivity
|
|||
mWasFirstTabShownAfterActivityUnhidden = false; // onStart indicates we were hidden.
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||
super.onRestoreInstanceState(savedInstanceState);
|
||||
|
||||
final SparseArray<Parcelable> stateToRestore =
|
||||
savedInstanceState.getSparseParcelableArray(GECKOVIEW_STATE_BUNDLE);
|
||||
restoreGeckoViewState(stateToRestore);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the given state into our GeckoView and clears any state we might have kept locally
|
||||
* within our process, as it has now become obsolete.
|
||||
*/
|
||||
private void restoreGeckoViewState(final SparseArray<Parcelable> state) {
|
||||
if (state != null) {
|
||||
mLayerView.restoreHierarchyState(state);
|
||||
}
|
||||
getGeckoApplication().setSavedState(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
|
|
@ -2534,6 +2578,10 @@ public abstract class GeckoApp extends GeckoActivity
|
|||
return mLayerView;
|
||||
}
|
||||
|
||||
protected GeckoApplication getGeckoApplication() {
|
||||
return (GeckoApplication) getApplicationContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setRequestedOrientationForCurrentActivity(int requestedActivityInfoOrientation) {
|
||||
// We want to support the Screen Orientation API, and it always makes sense to lock the
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import android.graphics.Bitmap;
|
|||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Parcelable;
|
||||
import android.os.Process;
|
||||
import android.os.SystemClock;
|
||||
import android.provider.MediaStore;
|
||||
|
|
@ -26,6 +27,7 @@ import android.support.multidex.MultiDex;
|
|||
import android.text.TextUtils;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.squareup.leakcanary.LeakCanary;
|
||||
import com.squareup.leakcanary.RefWatcher;
|
||||
|
|
@ -81,6 +83,10 @@ public class GeckoApplication extends Application
|
|||
|
||||
private LightweightTheme mLightweightTheme;
|
||||
|
||||
// GeckoApp *must* keep its GeckoView state around for as long as our app process (and
|
||||
// therefore Gecko) keeps running, even if Android clears the normal savedInstanceState.
|
||||
private SparseArray<Parcelable> mSavedState;
|
||||
|
||||
private RefWatcher mRefWatcher;
|
||||
|
||||
private final EventListener mListener = new EventListener();
|
||||
|
|
@ -641,6 +647,14 @@ public class GeckoApplication extends Application
|
|||
mLightweightTheme = new LightweightTheme(this);
|
||||
}
|
||||
|
||||
/* package */ void setSavedState(SparseArray<Parcelable> savedState) {
|
||||
mSavedState = savedState;
|
||||
}
|
||||
|
||||
/* package */ SparseArray<Parcelable> getSavedState() {
|
||||
return mSavedState;
|
||||
}
|
||||
|
||||
public static void createShortcut() {
|
||||
final Tab selectedTab = Tabs.getInstance().getSelectedTab();
|
||||
if (selectedTab != null) {
|
||||
|
|
|
|||
|
|
@ -201,6 +201,8 @@ public class UpdateServiceHelper {
|
|||
.replace("%DISTRIBUTION_VERSION%", "default")
|
||||
.replace("%MOZ_VERSION%", AppConstants.MOZILLA_VERSION);
|
||||
|
||||
Log.i(LOGTAG, "AUS Url is: " + url);
|
||||
|
||||
try {
|
||||
return new URI(url);
|
||||
} catch (java.net.URISyntaxException e) {
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ class AccessibilityTest : BaseSessionTest() {
|
|||
|
||||
private interface EventDelegate {
|
||||
fun onAccessibilityFocused(event: AccessibilityEvent) { }
|
||||
fun onAccessibilityFocusCleared(event: AccessibilityEvent) { }
|
||||
fun onClicked(event: AccessibilityEvent) { }
|
||||
fun onFocused(event: AccessibilityEvent) { }
|
||||
fun onSelected(event: AccessibilityEvent) { }
|
||||
|
|
@ -125,6 +126,7 @@ class AccessibilityTest : BaseSessionTest() {
|
|||
AccessibilityEvent.TYPE_VIEW_FOCUSED -> newDelegate.onFocused(event)
|
||||
AccessibilityEvent.TYPE_VIEW_CLICKED -> newDelegate.onClicked(event)
|
||||
AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED -> newDelegate.onAccessibilityFocused(event)
|
||||
AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED -> newDelegate.onAccessibilityFocusCleared(event)
|
||||
AccessibilityEvent.TYPE_VIEW_SELECTED -> newDelegate.onSelected(event)
|
||||
AccessibilityEvent.TYPE_VIEW_SCROLLED -> newDelegate.onScrolled(event)
|
||||
AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED -> newDelegate.onTextSelectionChanged(event)
|
||||
|
|
@ -192,6 +194,7 @@ class AccessibilityTest : BaseSessionTest() {
|
|||
assertThat("Label accessibility focused", node.className.toString(),
|
||||
equalTo("android.view.View"))
|
||||
assertThat("Text node should not be focusable", node.isFocusable, equalTo(false))
|
||||
assertThat("Text node should be a11y focused", node.isAccessibilityFocused, equalTo(true))
|
||||
assertThat("Text node should not be clickable", node.isClickable, equalTo(false))
|
||||
}
|
||||
})
|
||||
|
|
@ -207,9 +210,22 @@ class AccessibilityTest : BaseSessionTest() {
|
|||
assertThat("Editbox accessibility focused", node.className.toString(),
|
||||
equalTo("android.widget.EditText"))
|
||||
assertThat("Entry node should be focusable", node.isFocusable, equalTo(true))
|
||||
assertThat("Entry node should be a11y focused", node.isAccessibilityFocused, equalTo(true))
|
||||
assertThat("Entry node should be clickable", node.isClickable, equalTo(true))
|
||||
}
|
||||
})
|
||||
|
||||
provider.performAction(nodeId,
|
||||
AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null)
|
||||
|
||||
sessionRule.waitUntilCalled(object : EventDelegate {
|
||||
@AssertCalled(count = 1)
|
||||
override fun onAccessibilityFocusCleared(event: AccessibilityEvent) {
|
||||
assertThat("Accessibility focused node is now cleared", getSourceId(event), equalTo(nodeId))
|
||||
val node = createNodeInfo(nodeId)
|
||||
assertThat("Entry node should node be a11y focused", node.isAccessibilityFocused, equalTo(false))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@Test fun testTextEntryNode() {
|
||||
|
|
|
|||
|
|
@ -118,10 +118,6 @@ public class SessionAccessibility {
|
|||
if (mAttached) {
|
||||
node = mSession.getSettings().getFullAccessibilityTree() ?
|
||||
getNodeFromGecko(virtualDescendantId) : getNodeFromCache(virtualDescendantId);
|
||||
if (node != null) {
|
||||
node.setAccessibilityFocused(mAccessibilityFocusedNode == virtualDescendantId);
|
||||
node.setFocused(mFocusedNode == virtualDescendantId);
|
||||
}
|
||||
}
|
||||
|
||||
if (node == null) {
|
||||
|
|
@ -143,6 +139,9 @@ public class SessionAccessibility {
|
|||
final GeckoBundle data;
|
||||
|
||||
switch (action) {
|
||||
case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS:
|
||||
sendEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED, virtualViewId, CLASSNAME_VIEW, null);
|
||||
return true;
|
||||
case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS:
|
||||
if (virtualViewId == View.NO_ID) {
|
||||
sendEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED, View.NO_ID, CLASSNAME_WEBVIEW, null);
|
||||
|
|
@ -296,7 +295,8 @@ public class SessionAccessibility {
|
|||
return;
|
||||
}
|
||||
|
||||
boolean isRoot = nodeInfo.getInt("id") == View.NO_ID;
|
||||
final int id = nodeInfo.getInt("id");
|
||||
boolean isRoot = id == View.NO_ID;
|
||||
if (isRoot) {
|
||||
if (Build.VERSION.SDK_INT < 17 || mView.getDisplay() != null) {
|
||||
// When running junit tests we don't have a display
|
||||
|
|
@ -321,8 +321,6 @@ public class SessionAccessibility {
|
|||
// Add actions
|
||||
node.addAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT);
|
||||
node.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT);
|
||||
node.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
|
||||
node.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
|
||||
node.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY);
|
||||
node.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY);
|
||||
node.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER |
|
||||
|
|
@ -348,6 +346,14 @@ public class SessionAccessibility {
|
|||
// Other boolean properties to consider later:
|
||||
// setHeading, setImportantForAccessibility, setScreenReaderFocusable, setShowingHintText, setDismissable
|
||||
|
||||
if (mAccessibilityFocusedNode == id) {
|
||||
node.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
|
||||
node.setAccessibilityFocused(true);
|
||||
} else {
|
||||
node.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
|
||||
}
|
||||
node.setFocused(mFocusedNode == id);
|
||||
|
||||
// Bounds
|
||||
int[] b = nodeInfo.getIntArray("bounds");
|
||||
if (b != null) {
|
||||
|
|
@ -714,6 +720,11 @@ public class SessionAccessibility {
|
|||
}
|
||||
}
|
||||
break;
|
||||
case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED:
|
||||
if (mAccessibilityFocusedNode == sourceId) {
|
||||
mAccessibilityFocusedNode = 0;
|
||||
}
|
||||
break;
|
||||
case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED:
|
||||
mAccessibilityFocusedNode = sourceId;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -5334,7 +5334,11 @@ pref("dom.vr.autoactivate.enabled", false);
|
|||
// The threshold value of trigger inputs for VR controllers
|
||||
pref("dom.vr.controller_trigger_threshold", "0.1");
|
||||
// Enable external XR API integrations
|
||||
#if defined(XP_WIN) && defined(NIGHTLY_BUILD)
|
||||
pref("dom.vr.external.enabled", true);
|
||||
#else
|
||||
pref("dom.vr.external.enabled", false);
|
||||
#endif
|
||||
// Minimum number of milliseconds the browser will wait before attempting
|
||||
// to re-start the VR service after an enumeration returned no devices.
|
||||
pref("dom.vr.external.notdetected.timeout", 60000);
|
||||
|
|
@ -5423,8 +5427,8 @@ pref("dom.vr.poseprediction.enabled", true);
|
|||
// tests or in a headless kiosk system.
|
||||
pref("dom.vr.require-gesture", true);
|
||||
// Enable a separate process for VR module.
|
||||
#if defined(XP_WIN)
|
||||
pref("dom.vr.process.enabled", false);
|
||||
#if defined(XP_WIN) && defined(NIGHTLY_BUILD)
|
||||
pref("dom.vr.process.enabled", true);
|
||||
#endif
|
||||
// Puppet device, used for simulating VR hardware within tests and dev tools
|
||||
pref("dom.vr.puppet.enabled", false);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
</head>
|
||||
<body>
|
||||
<script>
|
||||
SimpleTest.requestCompleteLog();
|
||||
|
||||
// All the requests are sent to test_accept_header.sjs which will return
|
||||
// different content based on the queryString. When the queryString is 'get',
|
||||
|
|
@ -23,8 +24,7 @@ function test_last_request_and_continue(query, expected) {
|
|||
|
||||
function test_iframe() {
|
||||
let observer = new PerformanceObserver(function(list, obj) {
|
||||
obj.disconnect();
|
||||
|
||||
list.getEntries().forEach(entry => info(entry.name));
|
||||
list.getEntries().forEach(entry => {
|
||||
if (entry.name.endsWith("test_accept_header.sjs?iframe")) {
|
||||
obj.disconnect();
|
||||
|
|
@ -51,8 +51,7 @@ function test_image() {
|
|||
|
||||
function test_style() {
|
||||
let observer = new PerformanceObserver(function(list, obj) {
|
||||
obj.disconnect();
|
||||
|
||||
list.getEntries().forEach(entry => info(entry.name));
|
||||
list.getEntries().forEach(entry => {
|
||||
if (entry.name.endsWith("test_accept_header.sjs?style")) {
|
||||
obj.disconnect();
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
function handleRequest(request, response) {
|
||||
response.setStatusLine(request.httpVersion, "200", "OK");
|
||||
dump(`test_accept_header ${request.path}?${request.queryString}\n`);
|
||||
|
||||
if (request.queryString == "worker") {
|
||||
response.setHeader("Content-Type", "application/json", false);
|
||||
response.setHeader("Content-Type", "text/javascript", false);
|
||||
response.write("postMessage(42)");
|
||||
|
||||
setState("data", JSON.stringify({type: "worker", accept: request.getHeader("Accept") }));
|
||||
|
|
@ -39,7 +40,7 @@ function handleRequest(request, response) {
|
|||
}
|
||||
|
||||
if (request.queryString == "get") {
|
||||
response.setHeader("Content-Type", "text/javascript", false);
|
||||
response.setHeader("Content-Type", "application/json", false);
|
||||
response.write(getState("data"));
|
||||
|
||||
setState("data", "");
|
||||
|
|
|
|||
|
|
@ -44,20 +44,40 @@ following are valid:
|
|||
Auto Completion
|
||||
---------------
|
||||
|
||||
A `bash completion`_ script is bundled with mach. To enable it with ``bash``,
|
||||
add the following to your ``~/.bashrc``, ``~/.bash_profile`` or equivalent:
|
||||
A `bash completion`_ script is bundled with mach, it can be used with either ``bash`` or ``zsh``.
|
||||
|
||||
Bash
|
||||
~~~~
|
||||
|
||||
Add the following to your ``~/.bashrc``, ``~/.bash_profile`` or equivalent:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
source <srcdir>/python/mach/bash-completion.sh
|
||||
|
||||
This script can also be used with ``zsh``. Add this to your ``~/.zshrc`` or
|
||||
equivalent:
|
||||
.. tip::
|
||||
|
||||
Windows users using the default shell bundled with mozilla-build should source the completion
|
||||
script from ``~/.bash_profile`` (it may need to be created first).
|
||||
|
||||
Zsh
|
||||
~~~
|
||||
|
||||
Add this to your ``~/.zshrc`` or equivalent:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
autoload bashcompinit
|
||||
bashcompinit
|
||||
autoload -U bashcompinit && bashcompinit
|
||||
source <srcdir>/python/mach/bash-completion.sh
|
||||
|
||||
The ``compinit`` function also needs to be loaded, but if using a framework (like ``oh-my-zsh``),
|
||||
this will often be done for you. So if you see ``command not found: compdef``, you'll need to modify
|
||||
the above instructions to:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
autoload -U compinit && compinit
|
||||
autoload -U bashcompinit && bashcompinit
|
||||
source <srcdir>/python/mach/bash-completion.sh
|
||||
|
||||
Don't forget to substitute ``<srcdir>`` with the path to your checkout.
|
||||
|
|
|
|||
|
|
@ -72,19 +72,34 @@ class BuiltinCommands(object):
|
|||
args = args[i+1:]
|
||||
break
|
||||
|
||||
# If no command is typed yet, just offer the commands.
|
||||
if not command:
|
||||
print("\n".join(all_commands))
|
||||
return
|
||||
|
||||
handler = self.context.commands.command_handlers[command]
|
||||
# If a subcommand was typed, update the handler.
|
||||
for arg in args:
|
||||
if arg in handler.subcommand_handlers:
|
||||
handler = handler.subcommand_handlers[arg]
|
||||
break
|
||||
|
||||
parser = handler.parser
|
||||
targets = sorted(handler.subcommand_handlers.keys())
|
||||
if not is_help:
|
||||
targets.append('help')
|
||||
targets.extend(chain(*[action.option_strings for action in parser._actions]))
|
||||
if is_help:
|
||||
print("\n".join(targets))
|
||||
return
|
||||
|
||||
targets.append('help')
|
||||
|
||||
# The 'option_strings' are of the form [('-f', '--foo'), ('-b', '--bar'), ...].
|
||||
option_strings = [item[0] for item in handler.arguments]
|
||||
# Filter out positional arguments (we don't want to complete their metavar).
|
||||
option_strings = [opt for opt in option_strings if opt[0].startswith('-')]
|
||||
targets.extend(chain(*option_strings))
|
||||
|
||||
# If the command uses its own ArgumentParser, extract options from there as well.
|
||||
if handler.parser:
|
||||
targets.extend(chain(*[action.option_strings
|
||||
for action in handler.parser._actions]))
|
||||
|
||||
print("\n".join(targets))
|
||||
|
|
|
|||
|
|
@ -299,6 +299,30 @@ raptor-tp6-8-chrome:
|
|||
- --test=raptor-tp6-8
|
||||
- --app=chrome
|
||||
|
||||
raptor-tp6-9-firefox:
|
||||
description: "Raptor tp6-9 on Firefox"
|
||||
try-name: raptor-tp6-9-firefox
|
||||
treeherder-symbol: Rap(tp6-9)
|
||||
run-on-projects: ['try', 'mozilla-central']
|
||||
tier: 2
|
||||
mozharness:
|
||||
extra-options:
|
||||
- --test=raptor-tp6-9
|
||||
|
||||
raptor-tp6-9-chrome:
|
||||
description: "Raptor tp6-9 on Chrome"
|
||||
try-name: raptor-tp6-9-chrome
|
||||
treeherder-symbol: Rap-C(tp6-9)
|
||||
run-on-projects: ['try', 'mozilla-central']
|
||||
tier:
|
||||
by-test-platform:
|
||||
linux64.*: 3
|
||||
default: 2
|
||||
mozharness:
|
||||
extra-options:
|
||||
- --test=raptor-tp6-9
|
||||
- --app=chrome
|
||||
|
||||
raptor-tp6-10-firefox:
|
||||
description: "Raptor tp6-10 on Firefox"
|
||||
try-name: raptor-tp6-10-firefox
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ raptor-firefox:
|
|||
- raptor-tp6-6-firefox
|
||||
- raptor-tp6-7-firefox
|
||||
- raptor-tp6-8-firefox
|
||||
- raptor-tp6-9-firefox
|
||||
- raptor-tp6-10-firefox
|
||||
- raptor-speedometer-firefox
|
||||
- raptor-stylebench-firefox
|
||||
|
|
@ -121,6 +122,7 @@ raptor-chrome:
|
|||
- raptor-tp6-6-chrome
|
||||
- raptor-tp6-7-chrome
|
||||
- raptor-tp6-8-chrome
|
||||
- raptor-tp6-9-firefox
|
||||
- raptor-tp6-10-chrome
|
||||
- raptor-speedometer-chrome
|
||||
- raptor-stylebench-chrome
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ def process_leak_log(leak_log_file, leak_thresholds=None,
|
|||
|
||||
# This list is based on kGeckoProcessTypeString. ipdlunittest processes likely
|
||||
# are not going to produce leak logs we will ever see.
|
||||
knownProcessTypes = ["default", "plugin", "tab", "gmplugin", "gpu", "rdd"]
|
||||
knownProcessTypes = ["default", "plugin", "tab", "gmplugin", "gpu", "rdd", "vr"]
|
||||
|
||||
for processType in knownProcessTypes:
|
||||
log.info("TEST-INFO | leakcheck | %s process: leak threshold set at %d bytes"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
[
|
||||
{
|
||||
"size": 11627712,
|
||||
"visibility": "public",
|
||||
"digest": "a0dd4ccb99bac02a38b3c67baa08296c3e894837aba1c1b0750c592db6ff962ab0c61f557ffb45c2ea77e95345954a0786bf764448d090cc6cf76679d1a8a616",
|
||||
"algorithm": "sha512",
|
||||
"filename": "mitmproxy-tp6-pinterest.zip",
|
||||
"unpack": true
|
||||
}
|
||||
]
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
[include:tests/raptor-tp6-6.ini]
|
||||
[include:tests/raptor-tp6-7.ini]
|
||||
[include:tests/raptor-tp6-8.ini]
|
||||
[include:tests/raptor-tp6-9.ini]
|
||||
[include:tests/raptor-tp6-10.ini]
|
||||
|
||||
# raptor benchmark tests
|
||||
|
|
|
|||
34
testing/raptor/raptor/tests/raptor-tp6-9.ini
Normal file
34
testing/raptor/raptor/tests/raptor-tp6-9.ini
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# 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/.
|
||||
|
||||
# raptor tp6-9
|
||||
|
||||
[DEFAULT]
|
||||
type = pageload
|
||||
playback = mitmproxy
|
||||
playback_binary_manifest = mitmproxy-rel-bin-{platform}.manifest
|
||||
python3_win_manifest = python3{x64}.manifest
|
||||
page_cycles = 25
|
||||
unit = ms
|
||||
lower_is_better = true
|
||||
alert_threshold = 2.0
|
||||
# TTI/TTFI can take a while on some pages, and requires at least 5 seconds
|
||||
# beyond typical pageload time
|
||||
page_timeout = 30000
|
||||
gecko_profile_interval = 1
|
||||
gecko_profile_entries = 2000000
|
||||
|
||||
[raptor-tp6-pinterest-firefox]
|
||||
apps = firefox
|
||||
test_url = https://pinterest.com/
|
||||
playback_pageset_manifest = mitmproxy-recordings-raptor-pinterest.manifest
|
||||
playback_recordings = pinterest.mp
|
||||
measure = fnbpaint, dcf, ttfi, loadtime
|
||||
|
||||
[raptor-tp6-pinterest-chrome]
|
||||
apps = chrome
|
||||
test_url = https://pinterest.com/
|
||||
playback_pageset_manifest = mitmproxy-recordings-raptor-pinterest.manifest
|
||||
playback_recordings = pinterest.mp
|
||||
measure = fcp, loadtime
|
||||
|
|
@ -25,6 +25,7 @@
|
|||
"*://*.instagram.com/*",
|
||||
"*://*.microsoft.com/*",
|
||||
"*://*.paypal.com/*",
|
||||
"*://*.pinterest.com/*",
|
||||
"*://*.reddit.com/*",
|
||||
"*://*.twitter.com/*",
|
||||
"*://*.vice.com/*",
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
lsan-allowed: [Alloc, AllocateProtoAndIfaceCache, EntrySlotOrCreate, Realloc, alloc_system::platform::_$LT$impl$u20$core..alloc..GlobalAlloc$u20$for$u20$alloc_system..System$GT$::alloc, alloc_system::platform::_$LT$impl$u20$core..alloc..GlobalAlloc$u20$for$u20$alloc_system..System$GT$::realloc, mozilla::dom::ChromeUtils::GenerateQI, mozilla::dom::Performance::CreateForMainThread, mozilla::dom::PerformanceMainThread::CreateNavigationTimingEntry, mozilla::net::nsStandardURL::TemplatedMutator]
|
||||
leak-threshold: [tab:358400]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
[MediaRecorder-pause-resume.html]
|
||||
[MediaRecorder handles pause() and resume() calls appropriately in state and events]
|
||||
expected: FAIL
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
[MediaRecorder-stop.html]
|
||||
expected: TIMEOUT
|
||||
[MediaRecorder will stop recording and fire a stop event when stop() is called]
|
||||
expected: FAIL
|
||||
expected: NOTRUN
|
||||
|
||||
[MediaRecorder will stop recording and fire a stop event when all tracks are ended]
|
||||
expected: TIMEOUT
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>MediaRecorder Pause and Resume</title>
|
||||
<link rel="help" href="https://w3c.github.io/mediacapture-record/MediaRecorder.html#mediarecorder">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="canvas" width="200" height="200">
|
||||
</canvas>
|
||||
<script>
|
||||
function createVideoStream() {
|
||||
let canvas = document.getElementById("canvas");
|
||||
canvas.getContext('2d');
|
||||
return canvas.captureStream();
|
||||
}
|
||||
|
||||
function recordEvents(target, events) {
|
||||
let arr = [];
|
||||
for (let ev of events) {
|
||||
target.addEventListener(ev, _ => arr.push(ev));
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
promise_test(async () => {
|
||||
let video = createVideoStream();
|
||||
let recorder = new MediaRecorder(video);
|
||||
let events = recordEvents(recorder,
|
||||
["start", "stop", "dataavailable", "pause", "resume", "error"]);
|
||||
|
||||
recorder.start();
|
||||
assert_equals(recorder.state, "recording", "MediaRecorder has been started successfully");
|
||||
|
||||
recorder.pause();
|
||||
assert_equals(recorder.state, "paused", "MediaRecorder should be paused immediately following pause()");
|
||||
|
||||
// A second call to pause should be idempotent
|
||||
recorder.pause();
|
||||
assert_equals(recorder.state, "paused", "MediaRecorder should be paused immediately following pause()");
|
||||
|
||||
let event = await new Promise(r => recorder.onpause = r);
|
||||
assert_equals(event.type, "pause", "the event type should be pause");
|
||||
assert_true(event.isTrusted, "isTrusted should be true when the event is created by C++");
|
||||
|
||||
recorder.resume();
|
||||
assert_equals(recorder.state, "recording", "MediaRecorder state should be recording immediately following resume() call");
|
||||
|
||||
// A second call to resume should be idempotent
|
||||
recorder.resume();
|
||||
assert_equals(recorder.state, "recording", "MediaRecorder state should be recording immediately following resume() call");
|
||||
|
||||
event = await new Promise(r => recorder.onresume = r);
|
||||
assert_equals(event.type, "resume", "the event type should be resume");
|
||||
assert_true(event.isTrusted, "isTrusted should be true when the event is created by C++");
|
||||
|
||||
recorder.stop();
|
||||
await new Promise(r => recorder.onstop = r);
|
||||
|
||||
assert_array_equals(events, ["start", "pause", "resume", "dataavailable", "stop"],
|
||||
"Should have gotten expected events");
|
||||
}, "MediaRecorder handles pause() and resume() calls appropriately in state and events");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -16,35 +16,68 @@
|
|||
return canvas.captureStream();
|
||||
}
|
||||
|
||||
async_test(t => {
|
||||
function recordEvents(target, events) {
|
||||
let arr = [];
|
||||
for (let ev of events) {
|
||||
target.addEventListener(ev, _ => arr.push(ev));
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
promise_test(async t => {
|
||||
let video = createVideoStream();
|
||||
let recorder = new MediaRecorder(video);
|
||||
recorder.onstop = t.step_func(errorEvent => {
|
||||
assert_equals(errorEvent.type, 'stop', 'the error type should be stop');
|
||||
assert_true(errorEvent.isTrusted, 'isTrusted should be true when the event is created by C++');
|
||||
assert_equals(recorder.state, "inactive", "MediaRecorder has been stopped when all tracks are ended");
|
||||
t.done();
|
||||
});
|
||||
let events = recordEvents(recorder,
|
||||
["start", "stop", "dataavailable", "pause", "resume", "error"]);
|
||||
assert_equals(video.getVideoTracks().length, 1, "video mediastream starts with one track");
|
||||
recorder.start();
|
||||
assert_equals(recorder.state, "recording", "MediaRecorder has been started successfully");
|
||||
|
||||
video.getVideoTracks()[0].stop();
|
||||
assert_equals(recorder.state, "recording", "MediaRecorder state should be recording immediately following last track ending");
|
||||
let event = await new Promise(r => recorder.onstop = r);
|
||||
|
||||
assert_equals(event.type, "stop", "the event type should be stop");
|
||||
assert_true(event.isTrusted, "isTrusted should be true when the event is created by C++");
|
||||
assert_equals(recorder.state, "inactive", "MediaRecorder is inactive after stop event");
|
||||
|
||||
assert_array_equals(events, ["start", "dataavailable", "stop"],
|
||||
"Should have gotten expected events");
|
||||
|
||||
recorder.stop();
|
||||
await Promise.race([
|
||||
new Promise((_, reject) => recorder.onstop =
|
||||
_ => reject(new Error("stop() is idempotent"))),
|
||||
new Promise(r => t.step_timeout(r, 0))
|
||||
]);
|
||||
}, "MediaRecorder will stop recording and fire a stop event when all tracks are ended");
|
||||
|
||||
async_test(t => {
|
||||
promise_test(async t => {
|
||||
let video = createVideoStream();
|
||||
let recorder = new MediaRecorder(video);
|
||||
recorder.onstop = t.step_func(errorEvent => {
|
||||
assert_equals(errorEvent.type, 'stop', 'the error type should be stop');
|
||||
assert_true(errorEvent.isTrusted, 'isTrusted should be true when the event is created by C++');
|
||||
assert_equals(recorder.state, "inactive", "MediaRecorder has been stopped when stop() is called");
|
||||
t.done();
|
||||
});
|
||||
let events = recordEvents(recorder,
|
||||
["start", "stop", "dataavailable", "pause", "resume", "error"]);
|
||||
recorder.start();
|
||||
assert_equals(recorder.state, "recording", "MediaRecorder has been started successfully");
|
||||
|
||||
recorder.stop();
|
||||
assert_equals(recorder.state, "recording", "State should remain the same until stop event is fired");
|
||||
assert_equals(recorder.state, "inactive", "MediaRecorder state should be inactive immediately following stop() call");
|
||||
|
||||
let event = await new Promise (r => recorder.onstop = r);
|
||||
assert_equals(event.type, "stop", "the event type should be stop");
|
||||
assert_true(event.isTrusted, "isTrusted should be true when the event is created by C++");
|
||||
assert_equals(recorder.state, "inactive", "MediaRecorder is inactive after stop event");
|
||||
|
||||
assert_array_equals(events, ["start", "dataavailable", "stop"],
|
||||
"Should have gotten expected events");
|
||||
|
||||
recorder.stop();
|
||||
await Promise.race([
|
||||
new Promise((_, reject) => recorder.onstop =
|
||||
_ => reject(new Error("stop() is idempotent"))),
|
||||
new Promise(r => t.step_timeout(r, 0))
|
||||
]);
|
||||
}, "MediaRecorder will stop recording and fire a stop event when stop() is called");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -48,6 +48,9 @@ with Files('gmp-sources/*'):
|
|||
with Files('tests/browser/browser_audio*'):
|
||||
BUG_COMPONENT = ('Core', 'Audio/Video: Playback')
|
||||
|
||||
with Files('tests/browser/browser_autoplay*'):
|
||||
BUG_COMPONENT = ('Core', 'Audio/Video: Playback')
|
||||
|
||||
with Files('tests/browser/*block*'):
|
||||
BUG_COMPONENT = ('Core', 'Audio/Video: Playback')
|
||||
|
||||
|
|
|
|||
|
|
@ -377,17 +377,22 @@ class MozBrowser extends MozElementMixin(XULFrameElement) {
|
|||
|
||||
set docShellIsActive(val) {
|
||||
if (this.isRemoteBrowser) {
|
||||
this.frameLoader.tabParent.docShellIsActive = val;
|
||||
return val;
|
||||
let { frameLoader } = this;
|
||||
if (frameLoader && frameLoader.tabParent) {
|
||||
frameLoader.tabParent.docShellIsActive = val;
|
||||
}
|
||||
} else if (this.docShell) {
|
||||
this.docShell.isActive = val;
|
||||
}
|
||||
if (this.docShell)
|
||||
return this.docShell.isActive = val;
|
||||
return false;
|
||||
}
|
||||
|
||||
get docShellIsActive() {
|
||||
if (this.isRemoteBrowser) {
|
||||
return this.frameLoader.tabParent.docShellIsActive;
|
||||
let { frameLoader } = this;
|
||||
if (frameLoader && frameLoader.tabParent) {
|
||||
return frameLoader.tabParent.docShellIsActive;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return this.docShell && this.docShell.isActive;
|
||||
}
|
||||
|
|
@ -396,11 +401,11 @@ class MozBrowser extends MozElementMixin(XULFrameElement) {
|
|||
if (this.isRemoteBrowser) {
|
||||
let { frameLoader } = this;
|
||||
if (frameLoader && frameLoader.tabParent) {
|
||||
return frameLoader.tabParent.renderLayers = val;
|
||||
frameLoader.tabParent.renderLayers = val;
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
this.docShellIsActive = val;
|
||||
}
|
||||
return this.docShellIsActive = val;
|
||||
}
|
||||
|
||||
get renderLayers() {
|
||||
|
|
@ -417,7 +422,7 @@ class MozBrowser extends MozElementMixin(XULFrameElement) {
|
|||
get hasLayers() {
|
||||
if (this.isRemoteBrowser) {
|
||||
let { frameLoader } = this;
|
||||
if (frameLoader.tabParent) {
|
||||
if (frameLoader && frameLoader.tabParent) {
|
||||
return frameLoader.tabParent.hasLayers;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -727,7 +732,6 @@ class MozBrowser extends MozElementMixin(XULFrameElement) {
|
|||
set userTypedValue(val) {
|
||||
this.urlbarChangeTracker.userTyped();
|
||||
this._userTypedValue = val;
|
||||
return val;
|
||||
}
|
||||
|
||||
get userTypedValue() {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ codespell:
|
|||
- mobile/locales/en-US/
|
||||
- netwerk/locales/en-US/
|
||||
- python/docs/
|
||||
- python/mach/docs/
|
||||
- python/mozlint/
|
||||
- python/safety/
|
||||
- services/sync/locales/en-US/
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
const NSMouseMoved = 5;
|
||||
|
||||
var gLeftWindow, gRightWindow, gIFrame;
|
||||
var gLeftWindow, gRightWindow, gBrowserElement;
|
||||
var gExpectedEvents = [];
|
||||
|
||||
function moveMouseTo(x, y, andThen) {
|
||||
|
|
@ -36,24 +36,21 @@ function openWindows() {
|
|||
gLeftWindow = open('empty_window.xul', '_blank', 'chrome,screenX=50,screenY=50,width=200,height=200');
|
||||
SimpleTest.waitForFocus(function () {
|
||||
gRightWindow = open('empty_window.xul', '', 'chrome,screenX=300,screenY=50,width=200,height=200');
|
||||
SimpleTest.waitForFocus(attachIFrameToRightWindow, gRightWindow);
|
||||
SimpleTest.waitForFocus(attachBrowserToLeftWindow, gRightWindow);
|
||||
}, gLeftWindow);
|
||||
}
|
||||
|
||||
function attachIFrameToRightWindow() {
|
||||
gIFrame = gLeftWindow.document.createElementNS(XUL_NS, "iframe");
|
||||
gIFrame.setAttribute("type", "content");
|
||||
gIFrame.setAttribute("clickthrough", "never");
|
||||
gIFrame.setAttribute("src", "file_bug596600.html");
|
||||
gIFrame.style.width = "100px";
|
||||
gIFrame.style.height = "100px";
|
||||
gIFrame.style.margin = "50px";
|
||||
gLeftWindow.document.documentElement.appendChild(gIFrame);
|
||||
gIFrame.addEventListener("load", function (e) {
|
||||
gIFrame.removeEventListener("load", arguments.callee, true);
|
||||
function attachBrowserToLeftWindow() {
|
||||
gBrowserElement = gLeftWindow.document.createXULElement("browser");
|
||||
gBrowserElement.setAttribute("type", "content");
|
||||
gBrowserElement.setAttribute("src", "file_bug596600.html");
|
||||
gBrowserElement.style.width = "100px";
|
||||
gBrowserElement.style.height = "100px";
|
||||
gBrowserElement.style.margin = "50px";
|
||||
gLeftWindow.document.documentElement.appendChild(gBrowserElement);
|
||||
gBrowserElement.addEventListener("load", function (e) {
|
||||
test1();
|
||||
}, true);
|
||||
|
||||
}, { capture: true, once: true });
|
||||
}
|
||||
|
||||
function test1() {
|
||||
|
|
@ -76,7 +73,7 @@ function test1() {
|
|||
moveMouseTo(80, 80, function () {
|
||||
ok(!expectMouseOver, "Should have got mouseover event");
|
||||
|
||||
// Move over the iframe, which has clickthrough="never".
|
||||
// Move over the browser
|
||||
expectMouseOut = true;
|
||||
moveMouseTo(150, 150, function () {
|
||||
ok (!expectMouseOut, "Should have got mouseout event");
|
||||
|
|
@ -89,12 +86,12 @@ function test1() {
|
|||
}
|
||||
|
||||
function test2() {
|
||||
// Make the iframe cover the whole window.
|
||||
gIFrame.style.margin = "0";
|
||||
gIFrame.style.width = gIFrame.style.height = "200px";
|
||||
// Make the browser cover the whole window.
|
||||
gBrowserElement.style.margin = "0";
|
||||
gBrowserElement.style.width = gBrowserElement.style.height = "200px";
|
||||
|
||||
// Add a box to the iframe at the left edge.
|
||||
var doc = gIFrame.contentDocument;
|
||||
// Add a box to the browser at the left edge.
|
||||
var doc = gBrowserElement.contentDocument;
|
||||
var box = doc.createElement("div");
|
||||
box.setAttribute("id", "box");
|
||||
box.style.position = "absolute";
|
||||
|
|
@ -105,7 +102,7 @@ function test2() {
|
|||
box.style.backgroundColor = "green";
|
||||
doc.body.appendChild(box);
|
||||
|
||||
ok(!box.matches(":hover"), "Box shouldn't be hovered (since the mouse isn't over it and since it's in a non-clickthrough iframe in a background window)");
|
||||
ok(!box.matches(":hover"), "Box shouldn't be hovered (since the mouse isn't over it and since it's in a non-clickthrough browser in a background window)");
|
||||
|
||||
// A function to waitForFocus and then wait for synthetic mouse
|
||||
// events to happen. Note that those happen off the refresh driver,
|
||||
|
|
@ -134,22 +131,22 @@ function test2() {
|
|||
|
||||
// Move the mouse over the box.
|
||||
moveMouseTo(100, 150, function () {
|
||||
ok(!box.matches(":hover"), "Box shouldn't be hovered (since it's in a non-clickthrough iframe in a background window)");
|
||||
ok(!box.matches(":hover"), "Box shouldn't be hovered (since it's in a non-clickthrough browser in a background window)");
|
||||
// Activate the left window.
|
||||
changeFocusAndAwaitSyntheticMouse(function () {
|
||||
ok(gIFrame.matches(":hover"), "iframe should be hovered");
|
||||
ok(gBrowserElement.matches(":hover"), "browser should be hovered");
|
||||
ok(box.matches(":hover"), "Box should be hovered");
|
||||
// De-activate the window (by activating the right window).
|
||||
changeFocusAndAwaitSyntheticMouse(function () {
|
||||
ok(!gIFrame.matches(":hover"), "iframe shouldn't be hovered");
|
||||
ok(!gBrowserElement.matches(":hover"), "browser shouldn't be hovered");
|
||||
ok(!box.matches(":hover"), "Box shouldn't be hovered");
|
||||
// Re-activate it.
|
||||
changeFocusAndAwaitSyntheticMouse(function () {
|
||||
ok(gIFrame.matches(":hover"), "iframe should be hovered");
|
||||
ok(gBrowserElement.matches(":hover"), "browser should be hovered");
|
||||
ok(box.matches(":hover"), "Box should be hovered");
|
||||
// Unhover box and iframe by moving the mouse outside the window.
|
||||
// Unhover box and browser by moving the mouse outside the window.
|
||||
moveMouseTo(0, 150, function () {
|
||||
ok(!gIFrame.matches(":hover"), "iframe shouldn't be hovered");
|
||||
ok(!gBrowserElement.matches(":hover"), "browser shouldn't be hovered");
|
||||
ok(!box.matches(":hover"), "box shouldn't be hovered");
|
||||
finalize();
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue