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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aRole == roles::HEADING) {
|
if (aRole == roles::HEADING && aAttributes) {
|
||||||
|
// The heading level is an attribute, so we need that.
|
||||||
nsString level;
|
nsString level;
|
||||||
rv = aAttributes->GetStringProperty(NS_LITERAL_CSTRING("level"), level);
|
rv = aAttributes->GetStringProperty(NS_LITERAL_CSTRING("level"), level);
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
|
@ -411,7 +412,7 @@ bool AccessibleWrap::WrapperRangeInfo(double* aCurVal, double* aMinVal,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mozilla::java::GeckoBundle::LocalRef AccessibleWrap::ToBundle() {
|
mozilla::java::GeckoBundle::LocalRef AccessibleWrap::ToBundle(bool aSmall) {
|
||||||
nsAutoString name;
|
nsAutoString name;
|
||||||
Name(name);
|
Name(name);
|
||||||
nsAutoString textValue;
|
nsAutoString textValue;
|
||||||
|
|
@ -419,6 +420,10 @@ mozilla::java::GeckoBundle::LocalRef AccessibleWrap::ToBundle() {
|
||||||
nsAutoString nodeID;
|
nsAutoString nodeID;
|
||||||
WrapperDOMNodeID(nodeID);
|
WrapperDOMNodeID(nodeID);
|
||||||
|
|
||||||
|
if (aSmall) {
|
||||||
|
return ToBundle(State(), Bounds(), ActionCount(), name, textValue, nodeID);
|
||||||
|
}
|
||||||
|
|
||||||
double curValue = UnspecifiedNaN<double>();
|
double curValue = UnspecifiedNaN<double>();
|
||||||
double minValue = UnspecifiedNaN<double>();
|
double minValue = UnspecifiedNaN<double>();
|
||||||
double maxValue = UnspecifiedNaN<double>();
|
double maxValue = UnspecifiedNaN<double>();
|
||||||
|
|
@ -513,63 +518,66 @@ mozilla::java::GeckoBundle::LocalRef AccessibleWrap::ToBundle(
|
||||||
GECKOBUNDLE_PUT(nodeInfo, "rangeInfo", rangeInfo);
|
GECKOBUNDLE_PUT(nodeInfo, "rangeInfo", rangeInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsString inputTypeAttr;
|
if (aAttributes) {
|
||||||
nsAccUtils::GetAccAttr(aAttributes, nsGkAtoms::textInputType, inputTypeAttr);
|
nsString inputTypeAttr;
|
||||||
int32_t inputType = GetInputType(inputTypeAttr);
|
nsAccUtils::GetAccAttr(aAttributes, nsGkAtoms::textInputType,
|
||||||
if (inputType) {
|
inputTypeAttr);
|
||||||
GECKOBUNDLE_PUT(nodeInfo, "inputType",
|
int32_t inputType = GetInputType(inputTypeAttr);
|
||||||
java::sdk::Integer::ValueOf(inputType));
|
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);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
nsString colSize;
|
nsString posinset;
|
||||||
rv = aAttributes->GetStringProperty(NS_LITERAL_CSTRING("child-item-count"),
|
nsresult rv = aAttributes->GetStringProperty(NS_LITERAL_CSTRING("posinset"),
|
||||||
colSize);
|
posinset);
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
int32_t rowCount;
|
int32_t rowIndex;
|
||||||
if (sscanf(NS_ConvertUTF16toUTF8(colSize).get(), "%d", &rowCount) > 0) {
|
if (sscanf(NS_ConvertUTF16toUTF8(posinset).get(), "%d", &rowIndex) > 0) {
|
||||||
GECKOBUNDLE_START(collectionInfo);
|
GECKOBUNDLE_START(collectionItemInfo);
|
||||||
GECKOBUNDLE_PUT(collectionInfo, "rowCount",
|
GECKOBUNDLE_PUT(collectionItemInfo, "rowIndex",
|
||||||
java::sdk::Integer::ValueOf(rowCount));
|
java::sdk::Integer::ValueOf(rowIndex));
|
||||||
GECKOBUNDLE_PUT(collectionInfo, "columnCount",
|
GECKOBUNDLE_PUT(collectionItemInfo, "columnIndex",
|
||||||
java::sdk::Integer::ValueOf(1));
|
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;
|
GECKOBUNDLE_PUT(nodeInfo, "collectionItemInfo", collectionItemInfo);
|
||||||
rv = aAttributes->GetStringProperty(NS_LITERAL_CSTRING("hierarchical"),
|
|
||||||
unused);
|
|
||||||
if (NS_SUCCEEDED(rv)) {
|
|
||||||
GECKOBUNDLE_PUT(collectionInfo, "isHierarchical",
|
|
||||||
java::sdk::Boolean::TRUE());
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (IsSelect()) {
|
nsString colSize;
|
||||||
int32_t selectionMode = (aState & states::MULTISELECTABLE) ? 2 : 1;
|
rv = aAttributes->GetStringProperty(NS_LITERAL_CSTRING("child-item-count"),
|
||||||
GECKOBUNDLE_PUT(collectionInfo, "selectionMode",
|
colSize);
|
||||||
java::sdk::Integer::ValueOf(selectionMode));
|
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;
|
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);
|
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(
|
mozilla::java::GeckoBundle::LocalRef ToBundle(
|
||||||
const uint64_t aState, const nsIntRect& aBounds,
|
const uint64_t aState, const nsIntRect& aBounds,
|
||||||
const uint8_t aActionCount, const nsString& aName,
|
const uint8_t aActionCount, const nsString& aName,
|
||||||
const nsString& aTextValue, const nsString& aDOMNodeID,
|
const nsString& aTextValue, const nsString& aDOMNodeID,
|
||||||
const double& aCurVal, const double& aMinVal, const double& aMaxVal,
|
const double& aCurVal = UnspecifiedNaN<double>(),
|
||||||
const double& aStep, nsIPersistentProperties* aAttributes);
|
const double& aMinVal = UnspecifiedNaN<double>(),
|
||||||
|
const double& aMaxVal = UnspecifiedNaN<double>(),
|
||||||
mozilla::java::GeckoBundle::LocalRef ToSmallBundle(
|
const double& aStep = UnspecifiedNaN<double>(),
|
||||||
const uint64_t aState, const nsIntRect& aBounds,
|
nsIPersistentProperties* aAttributes = nullptr);
|
||||||
const uint8_t aActionCount);
|
|
||||||
|
|
||||||
mozilla::java::GeckoBundle::LocalRef ToSmallBundle();
|
|
||||||
|
|
||||||
virtual void WrapperDOMNodeID(nsString& aDOMNodeID);
|
virtual void WrapperDOMNodeID(nsString& aDOMNodeID);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -133,10 +133,18 @@ void DocAccessibleWrap::CacheViewportCallback(nsITimer* aTimer,
|
||||||
auto uid = accessible->IsDoc() && accessible->AsDoc()->IPCDoc()
|
auto uid = accessible->IsDoc() && accessible->AsDoc()->IPCDoc()
|
||||||
? 0
|
? 0
|
||||||
: reinterpret_cast<uint64_t>(accessible->UniqueID());
|
: 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(
|
cacheData.AppendElement(
|
||||||
BatchData(accessible->Document()->IPCDoc(), uid, accessible->State(),
|
BatchData(accessible->Document()->IPCDoc(), uid, accessible->State(),
|
||||||
accessible->Bounds(), accessible->ActionCount(), nsString(),
|
accessible->Bounds(), accessible->ActionCount(), name,
|
||||||
nsString(), nsString(), UnspecifiedNaN<double>(),
|
textValue, nodeID, UnspecifiedNaN<double>(),
|
||||||
UnspecifiedNaN<double>(), UnspecifiedNaN<double>(),
|
UnspecifiedNaN<double>(), UnspecifiedNaN<double>(),
|
||||||
UnspecifiedNaN<double>(), nsTArray<Attribute>()));
|
UnspecifiedNaN<double>(), nsTArray<Attribute>()));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -333,10 +333,11 @@ void SessionAccessibility::ReplaceViewportCache(
|
||||||
if (aData.Length() == aAccessibles.Length()) {
|
if (aData.Length() == aAccessibles.Length()) {
|
||||||
const BatchData& data = aData.ElementAt(i);
|
const BatchData& data = aData.ElementAt(i);
|
||||||
auto bundle =
|
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);
|
infos->SetElement(i, bundle);
|
||||||
} else {
|
} else {
|
||||||
infos->SetElement(i, acc->ToSmallBundle());
|
infos->SetElement(i, acc->ToBundle(true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -380,10 +381,11 @@ void SessionAccessibility::UpdateCachedBounds(
|
||||||
if (aData.Length() == aAccessibles.Length()) {
|
if (aData.Length() == aAccessibles.Length()) {
|
||||||
const BatchData& data = aData.ElementAt(i);
|
const BatchData& data = aData.ElementAt(i);
|
||||||
auto bundle =
|
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);
|
infos->SetElement(i, bundle);
|
||||||
} else {
|
} else {
|
||||||
infos->SetElement(i, acc->ToSmallBundle());
|
infos->SetElement(i, acc->ToBundle(true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -411,6 +411,8 @@ mozilla::ipc::IPCResult DocAccessibleParent::RecvScrollingEvent(
|
||||||
#if defined(ANDROID)
|
#if defined(ANDROID)
|
||||||
ProxyScrollingEvent(target, aType, aScrollX, aScrollY, aMaxScrollX,
|
ProxyScrollingEvent(target, aType, aScrollX, aScrollY, aMaxScrollX,
|
||||||
aMaxScrollY);
|
aMaxScrollY);
|
||||||
|
#else
|
||||||
|
ProxyEvent(target, aType);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!nsCoreUtils::AccEventObserversExist()) {
|
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.download.useDownloadDir", true);
|
||||||
pref("services.sync.prefs.sync.browser.formfill.enable", 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.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.enabled", true);
|
||||||
pref("services.sync.prefs.sync.browser.newtabpage.pinned", true);
|
pref("services.sync.prefs.sync.browser.newtabpage.pinned", true);
|
||||||
pref("services.sync.prefs.sync.browser.offline-apps.notify", true);
|
pref("services.sync.prefs.sync.browser.offline-apps.notify", true);
|
||||||
|
|
|
||||||
|
|
@ -492,7 +492,7 @@ window._gBrowser = {
|
||||||
},
|
},
|
||||||
|
|
||||||
set userTypedValue(val) {
|
set userTypedValue(val) {
|
||||||
return this.selectedBrowser.userTypedValue = val;
|
this.selectedBrowser.userTypedValue = val;
|
||||||
},
|
},
|
||||||
|
|
||||||
get userTypedValue() {
|
get userTypedValue() {
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,9 @@ prefs =
|
||||||
browser.migration.version=9999999
|
browser.migration.version=9999999
|
||||||
browser.startup.record=true
|
browser.startup.record=true
|
||||||
gfx.canvas.willReadFrequently.enable=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 =
|
support-files =
|
||||||
head.js
|
head.js
|
||||||
[browser_appmenu.js]
|
[browser_appmenu.js]
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
/* Any copyright is dedicated to the Public Domain.
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
/* This test records which services, JS components, process scripts, and JS
|
/* This test records which services, JS components, frame scripts, process
|
||||||
* modules are loaded when creating a new content 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
|
* If you made changes that cause this test to fail, it's likely because you
|
||||||
* are loading more JS code during content process startup.
|
* are loading more JS code during content process startup.
|
||||||
|
|
@ -68,6 +68,23 @@ const whitelist = {
|
||||||
"resource://gre/modules/ExtensionUtils.jsm",
|
"resource://gre/modules/ExtensionUtils.jsm",
|
||||||
"resource://gre/modules/MessageChannel.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([
|
processScripts: new Set([
|
||||||
"chrome://global/content/process-content.js",
|
"chrome://global/content/process-content.js",
|
||||||
"resource:///modules/ContentObservers.js",
|
"resource:///modules/ContentObservers.js",
|
||||||
|
|
@ -89,6 +106,7 @@ const intermittently_loaded_whitelist = {
|
||||||
modules: new Set([
|
modules: new Set([
|
||||||
"resource://gre/modules/sessionstore/Utils.jsm",
|
"resource://gre/modules/sessionstore/Utils.jsm",
|
||||||
]),
|
]),
|
||||||
|
frameScripts: new Set([]),
|
||||||
processScripts: new Set([]),
|
processScripts: new Set([]),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -140,6 +158,12 @@ add_task(async function() {
|
||||||
|
|
||||||
let loadedInfo = await promise;
|
let loadedInfo = await promise;
|
||||||
|
|
||||||
|
// Gather loaded frame scripts.
|
||||||
|
loadedInfo.frameScripts = {};
|
||||||
|
for (let [uri] of Services.mm.getDelayedFrameScripts()) {
|
||||||
|
loadedInfo.frameScripts[uri] = "";
|
||||||
|
}
|
||||||
|
|
||||||
// Gather loaded process scripts.
|
// Gather loaded process scripts.
|
||||||
loadedInfo.processScripts = {};
|
loadedInfo.processScripts = {};
|
||||||
for (let [uri] of Services.ppmm.getDelayedProcessScripts()) {
|
for (let [uri] of Services.ppmm.getDelayedProcessScripts()) {
|
||||||
|
|
|
||||||
|
|
@ -2820,6 +2820,9 @@ void EventStateManager::DecideGestureEvent(WidgetGestureNotifyEvent* aEvent,
|
||||||
#ifdef XP_MACOSX
|
#ifdef XP_MACOSX
|
||||||
static bool NodeAllowsClickThrough(nsINode* aNode) {
|
static bool NodeAllowsClickThrough(nsINode* aNode) {
|
||||||
while (aNode) {
|
while (aNode) {
|
||||||
|
if (aNode->IsXULElement(nsGkAtoms::browser)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (aNode->IsXULElement()) {
|
if (aNode->IsXULElement()) {
|
||||||
mozilla::dom::Element* element = aNode->AsElement();
|
mozilla::dom::Element* element = aNode->AsElement();
|
||||||
static Element::AttrValuesArray strings[] = {nsGkAtoms::always,
|
static Element::AttrValuesArray strings[] = {nsGkAtoms::always,
|
||||||
|
|
|
||||||
|
|
@ -324,28 +324,30 @@ class MediaRecorder::Session : public PrincipalChangeObserver<MediaStreamTrack>,
|
||||||
RefPtr<Session> mSession;
|
RefPtr<Session> mSession;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fire start event and set mimeType, run in main thread task.
|
// Fire a named event, run in main thread task.
|
||||||
class DispatchStartEventRunnable : public Runnable {
|
class DispatchEventRunnable : public Runnable {
|
||||||
public:
|
public:
|
||||||
explicit DispatchStartEventRunnable(Session* aSession)
|
explicit DispatchEventRunnable(Session* aSession,
|
||||||
: Runnable("dom::MediaRecorder::Session::DispatchStartEventRunnable"),
|
const nsAString& aEventName)
|
||||||
mSession(aSession) {}
|
: Runnable("dom::MediaRecorder::Session::DispatchEventRunnable"),
|
||||||
|
mSession(aSession),
|
||||||
|
mEventName(aEventName) {}
|
||||||
|
|
||||||
NS_IMETHOD Run() override {
|
NS_IMETHOD Run() override {
|
||||||
LOG(LogLevel::Debug,
|
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());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
NS_ENSURE_TRUE(mSession->mRecorder, NS_OK);
|
NS_ENSURE_TRUE(mSession->mRecorder, NS_OK);
|
||||||
RefPtr<MediaRecorder> recorder = mSession->mRecorder;
|
mSession->mRecorder->DispatchSimpleEvent(mEventName);
|
||||||
|
|
||||||
recorder->DispatchSimpleEvent(NS_LITERAL_STRING("start"));
|
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RefPtr<Session> mSession;
|
RefPtr<Session> mSession;
|
||||||
|
nsString mEventName;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Main thread task.
|
// Main thread task.
|
||||||
|
|
@ -591,6 +593,8 @@ class MediaRecorder::Session : public PrincipalChangeObserver<MediaStreamTrack>,
|
||||||
}
|
}
|
||||||
|
|
||||||
mEncoder->Suspend(TimeStamp::Now());
|
mEncoder->Suspend(TimeStamp::Now());
|
||||||
|
NS_DispatchToMainThread(
|
||||||
|
new DispatchEventRunnable(this, NS_LITERAL_STRING("pause")));
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -603,6 +607,8 @@ class MediaRecorder::Session : public PrincipalChangeObserver<MediaStreamTrack>,
|
||||||
}
|
}
|
||||||
|
|
||||||
mEncoder->Resume(TimeStamp::Now());
|
mEncoder->Resume(TimeStamp::Now());
|
||||||
|
NS_DispatchToMainThread(
|
||||||
|
new DispatchEventRunnable(this, NS_LITERAL_STRING("resume")));
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -983,7 +989,8 @@ class MediaRecorder::Session : public PrincipalChangeObserver<MediaStreamTrack>,
|
||||||
if (mRunningState.isOk() &&
|
if (mRunningState.isOk() &&
|
||||||
(mRunningState.unwrap() == RunningState::Idling ||
|
(mRunningState.unwrap() == RunningState::Idling ||
|
||||||
mRunningState.unwrap() == RunningState::Starting)) {
|
mRunningState.unwrap() == RunningState::Starting)) {
|
||||||
NS_DispatchToMainThread(new DispatchStartEventRunnable(this));
|
NS_DispatchToMainThread(
|
||||||
|
new DispatchEventRunnable(this, NS_LITERAL_STRING("start")));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rv == NS_OK) {
|
if (rv == NS_OK) {
|
||||||
|
|
@ -1050,7 +1057,8 @@ class MediaRecorder::Session : public PrincipalChangeObserver<MediaStreamTrack>,
|
||||||
}
|
}
|
||||||
self->mMimeType = mime;
|
self->mMimeType = mime;
|
||||||
self->mRecorder->SetMimeType(self->mMimeType);
|
self->mRecorder->SetMimeType(self->mMimeType);
|
||||||
auto startEvent = MakeRefPtr<DispatchStartEventRunnable>(self);
|
auto startEvent = MakeRefPtr<DispatchEventRunnable>(
|
||||||
|
self, NS_LITERAL_STRING("start"));
|
||||||
startEvent->Run();
|
startEvent->Run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1323,7 +1331,6 @@ void MediaRecorder::Stop(ErrorResult& aResult) {
|
||||||
LOG(LogLevel::Debug, ("MediaRecorder.Stop %p", this));
|
LOG(LogLevel::Debug, ("MediaRecorder.Stop %p", this));
|
||||||
MediaRecorderReporter::RemoveMediaRecorder(this);
|
MediaRecorderReporter::RemoveMediaRecorder(this);
|
||||||
if (mState == RecordingState::Inactive) {
|
if (mState == RecordingState::Inactive) {
|
||||||
aResult.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mState = RecordingState::Inactive;
|
mState = RecordingState::Inactive;
|
||||||
|
|
@ -1332,12 +1339,16 @@ void MediaRecorder::Stop(ErrorResult& aResult) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaRecorder::Pause(ErrorResult& aResult) {
|
void MediaRecorder::Pause(ErrorResult& aResult) {
|
||||||
LOG(LogLevel::Debug, ("MediaRecorder.Pause"));
|
LOG(LogLevel::Debug, ("MediaRecorder.Pause %p", this));
|
||||||
if (mState == RecordingState::Inactive) {
|
if (mState == RecordingState::Inactive) {
|
||||||
aResult.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
aResult.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mState == RecordingState::Paused) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
MOZ_ASSERT(mSessions.Length() > 0);
|
MOZ_ASSERT(mSessions.Length() > 0);
|
||||||
nsresult rv = mSessions.LastElement()->Pause();
|
nsresult rv = mSessions.LastElement()->Pause();
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
|
|
@ -1346,16 +1357,19 @@ void MediaRecorder::Pause(ErrorResult& aResult) {
|
||||||
}
|
}
|
||||||
|
|
||||||
mState = RecordingState::Paused;
|
mState = RecordingState::Paused;
|
||||||
DispatchSimpleEvent(NS_LITERAL_STRING("pause"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaRecorder::Resume(ErrorResult& aResult) {
|
void MediaRecorder::Resume(ErrorResult& aResult) {
|
||||||
LOG(LogLevel::Debug, ("MediaRecorder.Resume"));
|
LOG(LogLevel::Debug, ("MediaRecorder.Resume %p", this));
|
||||||
if (mState == RecordingState::Inactive) {
|
if (mState == RecordingState::Inactive) {
|
||||||
aResult.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
aResult.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mState == RecordingState::Recording) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
MOZ_ASSERT(mSessions.Length() > 0);
|
MOZ_ASSERT(mSessions.Length() > 0);
|
||||||
nsresult rv = mSessions.LastElement()->Resume();
|
nsresult rv = mSessions.LastElement()->Resume();
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
|
|
@ -1364,7 +1378,6 @@ void MediaRecorder::Resume(ErrorResult& aResult) {
|
||||||
}
|
}
|
||||||
|
|
||||||
mState = RecordingState::Recording;
|
mState = RecordingState::Recording;
|
||||||
DispatchSimpleEvent(NS_LITERAL_STRING("resume"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaRecorder::RequestData(ErrorResult& aResult) {
|
void MediaRecorder::RequestData(ErrorResult& aResult) {
|
||||||
|
|
@ -1576,15 +1589,12 @@ void MediaRecorder::DispatchSimpleEvent(const nsAString& aStr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
|
rv = DOMEventTargetHelper::DispatchTrustedEvent(aStr);
|
||||||
event->InitEvent(aStr, false, false);
|
if (NS_FAILED(rv)) {
|
||||||
event->SetTrusted(true);
|
LOG(LogLevel::Error,
|
||||||
|
("MediaRecorder.DispatchSimpleEvent: DispatchTrustedEvent failed %p",
|
||||||
IgnoredErrorResult res;
|
this));
|
||||||
DispatchEvent(*event, res);
|
|
||||||
if (res.Failed()) {
|
|
||||||
NS_ERROR("Failed to dispatch the event!!!");
|
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>();
|
aInputBuffer.data_size = aBuffer.mData().Size<uint8_t>();
|
||||||
|
|
||||||
if (aBuffer.mEncryptionScheme() > GMPEncryptionScheme::kGMPEncryptionNone) {
|
if (aBuffer.mEncryptionScheme() > GMPEncryptionScheme::kGMPEncryptionNone) {
|
||||||
// Cbcs is not yet supported, so we expect only cenc if the buffer us
|
|
||||||
// encrypted
|
|
||||||
MOZ_ASSERT(aBuffer.mEncryptionScheme() ==
|
MOZ_ASSERT(aBuffer.mEncryptionScheme() ==
|
||||||
GMPEncryptionScheme::kGMPEncryptionCenc);
|
GMPEncryptionScheme::kGMPEncryptionCenc ||
|
||||||
|
aBuffer.mEncryptionScheme() ==
|
||||||
|
GMPEncryptionScheme::kGMPEncryptionCbcs);
|
||||||
aInputBuffer.key_id = aBuffer.mKeyId().Elements();
|
aInputBuffer.key_id = aBuffer.mKeyId().Elements();
|
||||||
aInputBuffer.key_id_size = aBuffer.mKeyId().Length();
|
aInputBuffer.key_id_size = aBuffer.mKeyId().Length();
|
||||||
|
|
||||||
|
|
@ -595,6 +595,8 @@ static void InitInputBuffer(const CDMInputBuffer& aBuffer,
|
||||||
aInputBuffer.encryption_scheme =
|
aInputBuffer.encryption_scheme =
|
||||||
ConvertToCdmEncryptionScheme(aBuffer.mEncryptionScheme());
|
ConvertToCdmEncryptionScheme(aBuffer.mEncryptionScheme());
|
||||||
}
|
}
|
||||||
|
aInputBuffer.pattern.crypt_byte_block = aBuffer.mCryptByteBlock();
|
||||||
|
aInputBuffer.pattern.skip_byte_block = aBuffer.mSkipByteBlock();
|
||||||
aInputBuffer.timestamp = aBuffer.mTimestamp();
|
aInputBuffer.timestamp = aBuffer.mTimestamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -264,15 +264,23 @@ bool ChromiumCDMParent::InitCDMInputBuffer(gmp::CDMInputBuffer& aBuffer,
|
||||||
MOZ_ASSERT_UNREACHABLE("Should not have unrecognized encryption type");
|
MOZ_ASSERT_UNREACHABLE("Should not have unrecognized encryption type");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const nsTArray<uint8_t>& iv =
|
||||||
|
encryptionScheme != GMPEncryptionScheme::kGMPEncryptionCbcs
|
||||||
|
? crypto.mIV
|
||||||
|
: crypto.mConstantIV;
|
||||||
aBuffer = gmp::CDMInputBuffer(
|
aBuffer = gmp::CDMInputBuffer(
|
||||||
shmem, crypto.mKeyId, crypto.mIV, aSample->mTime.ToMicroseconds(),
|
shmem, crypto.mKeyId, iv, aSample->mTime.ToMicroseconds(),
|
||||||
aSample->mDuration.ToMicroseconds(), crypto.mPlainSizes,
|
aSample->mDuration.ToMicroseconds(), crypto.mPlainSizes,
|
||||||
crypto.mEncryptedSizes, encryptionScheme);
|
crypto.mEncryptedSizes, crypto.mCryptByteBlock, crypto.mSkipByteBlock,
|
||||||
|
encryptionScheme);
|
||||||
MOZ_ASSERT(
|
MOZ_ASSERT(
|
||||||
aBuffer.mEncryptionScheme() == GMPEncryptionScheme::kGMPEncryptionNone ||
|
aBuffer.mEncryptionScheme() == GMPEncryptionScheme::kGMPEncryptionNone ||
|
||||||
aBuffer.mEncryptionScheme() ==
|
aBuffer.mEncryptionScheme() ==
|
||||||
GMPEncryptionScheme::kGMPEncryptionCenc,
|
GMPEncryptionScheme::kGMPEncryptionCenc ||
|
||||||
"aBuffer should use either no encryption or cenc, other kinds are not "
|
aBuffer.mEncryptionScheme() ==
|
||||||
|
GMPEncryptionScheme::kGMPEncryptionCbcs,
|
||||||
|
"aBuffer should use no encryption, cenc, or cbcs, other kinds are not "
|
||||||
"yet supported");
|
"yet supported");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,8 @@ struct CDMInputBuffer {
|
||||||
int64_t mDuration;
|
int64_t mDuration;
|
||||||
uint16_t[] mClearBytes;
|
uint16_t[] mClearBytes;
|
||||||
uint32_t[] mCipherBytes;
|
uint32_t[] mCipherBytes;
|
||||||
|
uint8_t mCryptByteBlock;
|
||||||
|
uint8_t mSkipByteBlock;
|
||||||
GMPEncryptionScheme mEncryptionScheme;
|
GMPEncryptionScheme mEncryptionScheme;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ var manager = new MediaTestManager;
|
||||||
var operationTests = [
|
var operationTests = [
|
||||||
{
|
{
|
||||||
operations: ['stop'],
|
operations: ['stop'],
|
||||||
isValid: false
|
isValid: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
operations: ['requestData'],
|
operations: ['requestData'],
|
||||||
|
|
@ -70,7 +70,7 @@ var operationTests = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
operations: ['stop', 'start'],
|
operations: ['stop', 'start'],
|
||||||
isValid: false
|
isValid: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
operations: ['start', 'stop'],
|
operations: ['start', 'stop'],
|
||||||
|
|
@ -156,7 +156,7 @@ var operationTests = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
operations: ['start', 'stop', 'stop'],
|
operations: ['start', 'stop', 'stop'],
|
||||||
isValid: false
|
isValid: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
operations: ['start', 'pause', 'resume', 'resume'],
|
operations: ['start', 'pause', 'resume', 'resume'],
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#include "mozilla/gfx/Logging.h"
|
#include "mozilla/gfx/Logging.h"
|
||||||
#include "nsITimer.h"
|
#include "nsITimer.h"
|
||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
|
#include "VRGPUChild.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace gfx {
|
namespace gfx {
|
||||||
|
|
@ -150,6 +151,9 @@ void GPUProcessHost::Shutdown() {
|
||||||
|
|
||||||
// The channel might already be closed if we got here unexpectedly.
|
// The channel might already be closed if we got here unexpectedly.
|
||||||
if (!mChannelClosed) {
|
if (!mChannelClosed) {
|
||||||
|
if (VRGPUChild::IsCreated()) {
|
||||||
|
VRGPUChild::Get()->Close();
|
||||||
|
}
|
||||||
mGPUChild->SendShutdownVR();
|
mGPUChild->SendShutdownVR();
|
||||||
mGPUChild->Close();
|
mGPUChild->Close();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -378,7 +378,7 @@ class gfxPrefs final {
|
||||||
DECL_GFX_PREF(Once, "dom.vr.enabled", VREnabled, bool, false);
|
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.autoactivate.enabled", VRAutoActivateEnabled, bool, false);
|
||||||
DECL_GFX_PREF(Live, "dom.vr.controller_trigger_threshold", VRControllerTriggerThreshold, float, 0.1f);
|
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.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.external.quit.timeout", VRExternalQuitTimeout, int32_t, 10000);
|
||||||
DECL_GFX_PREF(Live, "dom.vr.navigation.timeout", VRNavigationTimeout, int32_t, 1000);
|
DECL_GFX_PREF(Live, "dom.vr.navigation.timeout", VRNavigationTimeout, int32_t, 1000);
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ VRManager::VRManager()
|
||||||
#if !defined(MOZ_WIDGET_ANDROID)
|
#if !defined(MOZ_WIDGET_ANDROID)
|
||||||
// The VR Service accesses all hardware from a separate process
|
// The VR Service accesses all hardware from a separate process
|
||||||
// and replaces the other VRSystemManager when enabled.
|
// and replaces the other VRSystemManager when enabled.
|
||||||
if (!gfxPrefs::VRProcessEnabled()) {
|
if (!gfxPrefs::VRProcessEnabled() || !XRE_IsGPUProcess()) {
|
||||||
VRServiceManager::Get().CreateService();
|
VRServiceManager::Get().CreateService();
|
||||||
}
|
}
|
||||||
if (VRServiceManager::Get().IsServiceValid()) {
|
if (VRServiceManager::Get().IsServiceValid()) {
|
||||||
|
|
@ -127,6 +127,7 @@ void VRManager::Destroy() {
|
||||||
VRServiceManager::Get().Shutdown();
|
VRServiceManager::Get().Shutdown();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
Shutdown();
|
||||||
mInitialized = false;
|
mInitialized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -140,7 +141,9 @@ void VRManager::Shutdown() {
|
||||||
if (VRServiceManager::Get().IsServiceValid()) {
|
if (VRServiceManager::Get().IsServiceValid()) {
|
||||||
VRServiceManager::Get().Stop();
|
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(
|
RefPtr<Runnable> task = NS_NewRunnableFunction(
|
||||||
"VRServiceManager::ShutdownVRProcess",
|
"VRServiceManager::ShutdownVRProcess",
|
||||||
[]() -> void { VRServiceManager::Get().ShutdownVRProcess(); });
|
[]() -> void { VRServiceManager::Get().ShutdownVRProcess(); });
|
||||||
|
|
@ -435,13 +438,15 @@ void VRManager::EnumerateVRDisplays() {
|
||||||
* is in progress
|
* is in progress
|
||||||
*/
|
*/
|
||||||
#if !defined(MOZ_WIDGET_ANDROID)
|
#if !defined(MOZ_WIDGET_ANDROID)
|
||||||
if (gfxPrefs::VRProcessEnabled() && !mVRServiceStarted) {
|
if (!mVRServiceStarted) {
|
||||||
VRServiceManager::Get().CreateVRProcess();
|
if (XRE_IsGPUProcess() && gfxPrefs::VRProcessEnabled()) {
|
||||||
mVRServiceStarted = true;
|
VRServiceManager::Get().CreateVRProcess();
|
||||||
} else if (!gfxPrefs::VRProcessEnabled()) {
|
|
||||||
if (VRServiceManager::Get().IsServiceValid()) {
|
|
||||||
VRServiceManager::Get().Start();
|
|
||||||
mVRServiceStarted = true;
|
mVRServiceStarted = true;
|
||||||
|
} else {
|
||||||
|
if (VRServiceManager::Get().IsServiceValid()) {
|
||||||
|
VRServiceManager::Get().Start();
|
||||||
|
mVRServiceStarted = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -486,7 +486,8 @@ void VRSystemManagerExternal::OpenShmem() {
|
||||||
mShmemFile =
|
mShmemFile =
|
||||||
CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
|
CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
|
||||||
sizeof(VRExternalShmem), kShmemName);
|
sizeof(VRExternalShmem), kShmemName);
|
||||||
MOZ_ASSERT(GetLastError() == 0);
|
MOZ_ASSERT(GetLastError() == 0 || GetLastError() == ERROR_ALREADY_EXISTS);
|
||||||
|
MOZ_ASSERT(mShmemFile);
|
||||||
} else {
|
} else {
|
||||||
mShmemFile = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, kShmemName);
|
mShmemFile = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, kShmemName);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,19 @@ static StaticRefPtr<VRGPUChild> sVRGPUChildSingleton;
|
||||||
|
|
||||||
/*static*/ void VRGPUChild::Shutdown() {
|
/*static*/ void VRGPUChild::Shutdown() {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
if (sVRGPUChildSingleton && !sVRGPUChildSingleton->IsClosed()) {
|
||||||
|
sVRGPUChildSingleton->Close();
|
||||||
|
}
|
||||||
sVRGPUChildSingleton = nullptr;
|
sVRGPUChildSingleton = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VRGPUChild::ActorDestroy(ActorDestroyReason aWhy) {
|
||||||
|
mClosed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VRGPUChild::IsClosed() {
|
||||||
|
return mClosed;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace gfx
|
} // namespace gfx
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
||||||
|
|
@ -21,12 +21,17 @@ class VRGPUChild final : public PVRGPUChild {
|
||||||
static bool IsCreated();
|
static bool IsCreated();
|
||||||
static void Shutdown();
|
static void Shutdown();
|
||||||
|
|
||||||
|
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||||
|
bool IsClosed();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit VRGPUChild() {}
|
explicit VRGPUChild() : mClosed(false) {}
|
||||||
~VRGPUChild() {}
|
~VRGPUChild() = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DISALLOW_COPY_AND_ASSIGN(VRGPUChild);
|
DISALLOW_COPY_AND_ASSIGN(VRGPUChild);
|
||||||
|
|
||||||
|
bool mClosed;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace gfx
|
} // namespace gfx
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,18 @@ namespace gfx {
|
||||||
|
|
||||||
using namespace ipc;
|
using namespace ipc;
|
||||||
|
|
||||||
VRGPUParent::VRGPUParent(ProcessId aChildProcessId) {
|
VRGPUParent::VRGPUParent(ProcessId aChildProcessId)
|
||||||
|
: mClosed(false) {
|
||||||
MOZ_COUNT_CTOR(VRGPUParent);
|
MOZ_COUNT_CTOR(VRGPUParent);
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
SetOtherProcessId(aChildProcessId);
|
SetOtherProcessId(aChildProcessId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VRGPUParent::~VRGPUParent() {
|
||||||
|
MOZ_COUNT_DTOR(VRGPUParent);
|
||||||
|
}
|
||||||
|
|
||||||
void VRGPUParent::ActorDestroy(ActorDestroyReason aWhy) {
|
void VRGPUParent::ActorDestroy(ActorDestroyReason aWhy) {
|
||||||
#if !defined(MOZ_WIDGET_ANDROID)
|
#if !defined(MOZ_WIDGET_ANDROID)
|
||||||
if (mVRService) {
|
if (mVRService) {
|
||||||
|
|
@ -28,6 +33,7 @@ void VRGPUParent::ActorDestroy(ActorDestroyReason aWhy) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
mClosed = true;
|
||||||
MessageLoop::current()->PostTask(
|
MessageLoop::current()->PostTask(
|
||||||
NewRunnableMethod("gfx::VRGPUParent::DeferredDestroy", this,
|
NewRunnableMethod("gfx::VRGPUParent::DeferredDestroy", this,
|
||||||
&VRGPUParent::DeferredDestroy));
|
&VRGPUParent::DeferredDestroy));
|
||||||
|
|
@ -41,7 +47,7 @@ void VRGPUParent::DeferredDestroy() { mSelfRef = nullptr; }
|
||||||
MessageLoop::current()->PostTask(NewRunnableMethod<Endpoint<PVRGPUParent>&&>(
|
MessageLoop::current()->PostTask(NewRunnableMethod<Endpoint<PVRGPUParent>&&>(
|
||||||
"gfx::VRGPUParent::Bind", vcp, &VRGPUParent::Bind, std::move(aEndpoint)));
|
"gfx::VRGPUParent::Bind", vcp, &VRGPUParent::Bind, std::move(aEndpoint)));
|
||||||
|
|
||||||
return vcp;
|
return vcp.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VRGPUParent::Bind(Endpoint<PVRGPUParent>&& aEndpoint) {
|
void VRGPUParent::Bind(Endpoint<PVRGPUParent>&& aEndpoint) {
|
||||||
|
|
@ -74,5 +80,9 @@ mozilla::ipc::IPCResult VRGPUParent::RecvStopVRService() {
|
||||||
return IPC_OK();
|
return IPC_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VRGPUParent::IsClosed() {
|
||||||
|
return mClosed;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace gfx
|
} // namespace gfx
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
@ -17,25 +17,28 @@ class VRGPUParent final : public PVRGPUParent {
|
||||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRGPUParent)
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRGPUParent)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit VRGPUParent(ProcessId aChildProcessId);
|
|
||||||
|
|
||||||
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
|
||||||
static RefPtr<VRGPUParent> CreateForGPU(Endpoint<PVRGPUParent>&& aEndpoint);
|
static RefPtr<VRGPUParent> CreateForGPU(Endpoint<PVRGPUParent>&& aEndpoint);
|
||||||
|
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||||
|
bool IsClosed();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
~VRGPUParent() = default;
|
|
||||||
|
|
||||||
void Bind(Endpoint<PVRGPUParent>&& aEndpoint);
|
void Bind(Endpoint<PVRGPUParent>&& aEndpoint);
|
||||||
virtual mozilla::ipc::IPCResult RecvStartVRService() override;
|
virtual mozilla::ipc::IPCResult RecvStartVRService() override;
|
||||||
virtual mozilla::ipc::IPCResult RecvStopVRService() override;
|
virtual mozilla::ipc::IPCResult RecvStopVRService() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
explicit VRGPUParent(ProcessId aChildProcessId);
|
||||||
|
~VRGPUParent();
|
||||||
|
|
||||||
void DeferredDestroy();
|
void DeferredDestroy();
|
||||||
|
|
||||||
RefPtr<VRGPUParent> mSelfRef;
|
RefPtr<VRGPUParent> mSelfRef;
|
||||||
#if !defined(MOZ_WIDGET_ANDROID)
|
#if !defined(MOZ_WIDGET_ANDROID)
|
||||||
RefPtr<VRService> mVRService;
|
RefPtr<VRService> mVRService;
|
||||||
#endif
|
#endif
|
||||||
|
bool mClosed;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(VRGPUParent);
|
DISALLOW_COPY_AND_ASSIGN(VRGPUParent);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#include "VRGPUParent.h"
|
#include "VRGPUParent.h"
|
||||||
#include "VRManager.h"
|
#include "VRManager.h"
|
||||||
#include "gfxConfig.h"
|
#include "gfxConfig.h"
|
||||||
|
#include "nsDebugImpl.h"
|
||||||
|
|
||||||
#include "mozilla/gfx/gfxVars.h"
|
#include "mozilla/gfx/gfxVars.h"
|
||||||
#include "mozilla/ipc/ProcessChild.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!");
|
NS_WARNING("Shutting down VR process early due to a crash!");
|
||||||
ProcessChild::QuickExit();
|
ProcessChild::QuickExit();
|
||||||
}
|
}
|
||||||
|
if (!mVRGPUParent->IsClosed()) {
|
||||||
|
mVRGPUParent->Close();
|
||||||
|
}
|
||||||
|
|
||||||
mVRGPUParent = nullptr;
|
mVRGPUParent = nullptr;
|
||||||
#if defined(XP_WIN)
|
#if defined(XP_WIN)
|
||||||
|
|
@ -123,6 +127,8 @@ bool VRParent::Init(base::ProcessId aParentPid, const char* aParentBuildID,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsDebugImpl::SetMultiprocessMode("VR");
|
||||||
|
|
||||||
// This must be checked before any IPDL message, which may hit sentinel
|
// This must be checked before any IPDL message, which may hit sentinel
|
||||||
// errors due to parent and content processes having different
|
// errors due to parent and content processes having different
|
||||||
// versions.
|
// versions.
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,6 @@ VRProcessChild::~VRProcessChild() { sVRParent = nullptr; }
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VRProcessChild::Init(int aArgc, char* aArgv[]) {
|
bool VRProcessChild::Init(int aArgc, char* aArgv[]) {
|
||||||
BackgroundHangMonitor::Startup();
|
|
||||||
|
|
||||||
char* parentBuildID = nullptr;
|
char* parentBuildID = nullptr;
|
||||||
for (int i = 1; i < aArgc; i++) {
|
for (int i = 1; i < aArgc; i++) {
|
||||||
if (!aArgv[i]) {
|
if (!aArgv[i]) {
|
||||||
|
|
|
||||||
|
|
@ -206,6 +206,10 @@ OculusSession::OculusSession()
|
||||||
OculusSession::~OculusSession() { Shutdown(); }
|
OculusSession::~OculusSession() { Shutdown(); }
|
||||||
|
|
||||||
bool OculusSession::Initialize(mozilla::gfx::VRSystemState& aSystemState) {
|
bool OculusSession::Initialize(mozilla::gfx::VRSystemState& aSystemState) {
|
||||||
|
if (!gfxPrefs::VREnabled() || !gfxPrefs::VROculusEnabled()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!CreateD3DObjects()) {
|
if (!CreateD3DObjects()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -530,14 +534,18 @@ bool OculusSession::LoadOvrLib() {
|
||||||
nsString libName;
|
nsString libName;
|
||||||
nsString searchPath;
|
nsString searchPath;
|
||||||
|
|
||||||
static const char dirSep = '\\';
|
for (;;) {
|
||||||
static const int pathLen = 260;
|
UINT requiredLength = ::GetSystemDirectoryW(
|
||||||
searchPath.SetCapacity(pathLen);
|
char16ptr_t(searchPath.BeginWriting()), searchPath.Length());
|
||||||
int realLen =
|
if (!requiredLength) {
|
||||||
::GetSystemDirectoryW(char16ptr_t(searchPath.BeginWriting()), pathLen);
|
break;
|
||||||
if (realLen != 0 && realLen < pathLen) {
|
}
|
||||||
searchPath.SetLength(realLen);
|
if (requiredLength < searchPath.Length()) {
|
||||||
libSearchPaths.AppendElement(searchPath);
|
searchPath.Truncate(requiredLength);
|
||||||
|
libSearchPaths.AppendElement(searchPath);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
searchPath.SetLength(requiredLength);
|
||||||
}
|
}
|
||||||
libName.AppendPrintf("LibOVRRT%d_%d.dll", BUILD_BITS, OVR_PRODUCT_VERSION);
|
libName.AppendPrintf("LibOVRRT%d_%d.dll", BUILD_BITS, OVR_PRODUCT_VERSION);
|
||||||
|
|
||||||
|
|
@ -554,13 +562,17 @@ bool OculusSession::LoadOvrLib() {
|
||||||
libName = _wgetenv(L"OVR_LIB_NAME");
|
libName = _wgetenv(L"OVR_LIB_NAME");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (libName.IsEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (uint32_t i = 0; i < libSearchPaths.Length(); ++i) {
|
for (uint32_t i = 0; i < libSearchPaths.Length(); ++i) {
|
||||||
nsString& libPath = libSearchPaths[i];
|
nsString& libPath = libSearchPaths[i];
|
||||||
nsString fullName;
|
nsString fullName;
|
||||||
if (libPath.Length() == 0) {
|
if (libPath.Length() == 0) {
|
||||||
fullName.Assign(libName);
|
fullName.Assign(libName);
|
||||||
} else {
|
} else {
|
||||||
fullName.AppendPrintf("%s%c%s", libPath.get(), dirSep, libName.get());
|
fullName.Assign(libPath + NS_LITERAL_STRING(u"\\") + libName);
|
||||||
}
|
}
|
||||||
|
|
||||||
mOvrLib = LoadLibraryWithFlags(fullName.get());
|
mOvrLib = LoadLibraryWithFlags(fullName.get());
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,9 @@ void VRServiceManager::ShutdownVRProcess() {
|
||||||
if (VRGPUChild::IsCreated()) {
|
if (VRGPUChild::IsCreated()) {
|
||||||
VRGPUChild* vrGPUChild = VRGPUChild::Get();
|
VRGPUChild* vrGPUChild = VRGPUChild::Get();
|
||||||
vrGPUChild->SendStopVRService();
|
vrGPUChild->SendStopVRService();
|
||||||
vrGPUChild->Close();
|
if (!vrGPUChild->IsClosed()) {
|
||||||
|
vrGPUChild->Close();
|
||||||
|
}
|
||||||
VRGPUChild::Shutdown();
|
VRGPUChild::Shutdown();
|
||||||
}
|
}
|
||||||
if (gfxPrefs::VRProcessEnabled()) {
|
if (gfxPrefs::VRProcessEnabled()) {
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ use gpu_types::{PrimitiveInstanceData, RasterizationSpace, GlyphInstance};
|
||||||
use gpu_types::{PrimitiveHeader, PrimitiveHeaderIndex, TransformPaletteId, TransformPalette};
|
use gpu_types::{PrimitiveHeader, PrimitiveHeaderIndex, TransformPaletteId, TransformPalette};
|
||||||
use internal_types::{FastHashMap, SavedTargetIndex, TextureSource};
|
use internal_types::{FastHashMap, SavedTargetIndex, TextureSource};
|
||||||
use picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive, PictureSurface};
|
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::{VisibleGradientTile, PrimitiveInstance, PrimitiveOpacity, SegmentInstanceIndex};
|
||||||
use prim_store::{BrushSegment, ClipMaskKind, ClipTaskIndex};
|
use prim_store::{BrushSegment, ClipMaskKind, ClipTaskIndex};
|
||||||
use prim_store::image::ImageSource;
|
use prim_store::image::ImageSource;
|
||||||
|
|
@ -583,7 +583,7 @@ impl AlphaBatchBuilder {
|
||||||
root_spatial_node_index: SpatialNodeIndex,
|
root_spatial_node_index: SpatialNodeIndex,
|
||||||
z_generator: &mut ZBufferIdGenerator,
|
z_generator: &mut ZBufferIdGenerator,
|
||||||
) {
|
) {
|
||||||
if prim_instance.bounding_rect.is_none() {
|
if prim_instance.visibility_info == PrimitiveVisibilityIndex::INVALID {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -601,15 +601,15 @@ impl AlphaBatchBuilder {
|
||||||
// wasteful. We should probably cache this in
|
// wasteful. We should probably cache this in
|
||||||
// the scroll node...
|
// the scroll node...
|
||||||
let transform_kind = transform_id.transform_kind();
|
let transform_kind = transform_id.transform_kind();
|
||||||
let bounding_rect = prim_instance.bounding_rect
|
let prim_info = &ctx.scratch.prim_info[prim_instance.visibility_info.0 as usize];
|
||||||
.as_ref()
|
let bounding_rect = &prim_info.clip_chain.pic_clip_rect;
|
||||||
.expect("bug");
|
|
||||||
let z_id = z_generator.next();
|
let z_id = z_generator.next();
|
||||||
|
|
||||||
// Get the clip task address for the global primitive, if one was set.
|
// Get the clip task address for the global primitive, if one was set.
|
||||||
let clip_task_address = get_clip_task_address(
|
let clip_task_address = get_clip_task_address(
|
||||||
&ctx.scratch.clip_mask_instances,
|
&ctx.scratch.clip_mask_instances,
|
||||||
prim_instance.clip_task_index,
|
prim_info.clip_task_index,
|
||||||
0,
|
0,
|
||||||
render_tasks,
|
render_tasks,
|
||||||
).unwrap_or(OPAQUE_TASK_ADDRESS);
|
).unwrap_or(OPAQUE_TASK_ADDRESS);
|
||||||
|
|
@ -631,7 +631,7 @@ impl AlphaBatchBuilder {
|
||||||
|
|
||||||
let prim_header = PrimitiveHeader {
|
let prim_header = PrimitiveHeader {
|
||||||
local_rect: prim_rect,
|
local_rect: prim_rect,
|
||||||
local_clip_rect: prim_instance.combined_local_clip_rect,
|
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||||
task_address,
|
task_address,
|
||||||
specific_prim_address: prim_cache_address,
|
specific_prim_address: prim_cache_address,
|
||||||
clip_task_address,
|
clip_task_address,
|
||||||
|
|
@ -691,7 +691,7 @@ impl AlphaBatchBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
let non_segmented_blend_mode = if !common_data.opacity.is_opaque ||
|
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
|
transform_kind == TransformedRectKind::Complex
|
||||||
{
|
{
|
||||||
specified_blend_mode
|
specified_blend_mode
|
||||||
|
|
@ -701,7 +701,7 @@ impl AlphaBatchBuilder {
|
||||||
|
|
||||||
let prim_header = PrimitiveHeader {
|
let prim_header = PrimitiveHeader {
|
||||||
local_rect: prim_rect,
|
local_rect: prim_rect,
|
||||||
local_clip_rect: prim_instance.combined_local_clip_rect,
|
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||||
task_address,
|
task_address,
|
||||||
specific_prim_address: prim_cache_address,
|
specific_prim_address: prim_cache_address,
|
||||||
clip_task_address,
|
clip_task_address,
|
||||||
|
|
@ -737,7 +737,7 @@ impl AlphaBatchBuilder {
|
||||||
transform_kind,
|
transform_kind,
|
||||||
render_tasks,
|
render_tasks,
|
||||||
z_id,
|
z_id,
|
||||||
prim_instance.clip_task_index,
|
prim_info.clip_task_index,
|
||||||
ctx,
|
ctx,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -754,7 +754,7 @@ impl AlphaBatchBuilder {
|
||||||
|
|
||||||
let prim_header = PrimitiveHeader {
|
let prim_header = PrimitiveHeader {
|
||||||
local_rect: prim_rect,
|
local_rect: prim_rect,
|
||||||
local_clip_rect: prim_instance.combined_local_clip_rect,
|
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||||
task_address,
|
task_address,
|
||||||
specific_prim_address: prim_cache_address,
|
specific_prim_address: prim_cache_address,
|
||||||
clip_task_address,
|
clip_task_address,
|
||||||
|
|
@ -891,7 +891,7 @@ impl AlphaBatchBuilder {
|
||||||
// helper methods, as we port more primitives to make
|
// helper methods, as we port more primitives to make
|
||||||
// use of interning.
|
// use of interning.
|
||||||
let blend_mode = if !common_data.opacity.is_opaque ||
|
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
|
transform_kind == TransformedRectKind::Complex
|
||||||
{
|
{
|
||||||
BlendMode::PremultipliedAlpha
|
BlendMode::PremultipliedAlpha
|
||||||
|
|
@ -901,7 +901,7 @@ impl AlphaBatchBuilder {
|
||||||
|
|
||||||
let prim_header = PrimitiveHeader {
|
let prim_header = PrimitiveHeader {
|
||||||
local_rect: prim_rect,
|
local_rect: prim_rect,
|
||||||
local_clip_rect: prim_instance.combined_local_clip_rect,
|
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||||
task_address,
|
task_address,
|
||||||
specific_prim_address: prim_cache_address,
|
specific_prim_address: prim_cache_address,
|
||||||
clip_task_address,
|
clip_task_address,
|
||||||
|
|
@ -943,7 +943,7 @@ impl AlphaBatchBuilder {
|
||||||
|
|
||||||
let prim_header = PrimitiveHeader {
|
let prim_header = PrimitiveHeader {
|
||||||
local_rect: picture.local_rect,
|
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,
|
task_address,
|
||||||
specific_prim_address: prim_cache_address,
|
specific_prim_address: prim_cache_address,
|
||||||
clip_task_address,
|
clip_task_address,
|
||||||
|
|
@ -955,6 +955,8 @@ impl AlphaBatchBuilder {
|
||||||
Picture3DContext::In { root_data: Some(ref list), .. } => {
|
Picture3DContext::In { root_data: Some(ref list), .. } => {
|
||||||
for child in list {
|
for child in list {
|
||||||
let prim_instance = &picture.prim_list.prim_instances[child.anchor];
|
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 {
|
let pic_index = match prim_instance.kind {
|
||||||
PrimitiveInstanceKind::Picture { pic_index, .. } => pic_index,
|
PrimitiveInstanceKind::Picture { pic_index, .. } => pic_index,
|
||||||
PrimitiveInstanceKind::LineDecoration { .. } |
|
PrimitiveInstanceKind::LineDecoration { .. } |
|
||||||
|
|
@ -972,17 +974,18 @@ impl AlphaBatchBuilder {
|
||||||
};
|
};
|
||||||
let pic = &ctx.prim_store.pictures[pic_index.0];
|
let pic = &ctx.prim_store.pictures[pic_index.0];
|
||||||
|
|
||||||
|
|
||||||
// Get clip task, if set, for the picture primitive.
|
// Get clip task, if set, for the picture primitive.
|
||||||
let clip_task_address = get_clip_task_address(
|
let clip_task_address = get_clip_task_address(
|
||||||
&ctx.scratch.clip_mask_instances,
|
&ctx.scratch.clip_mask_instances,
|
||||||
prim_instance.clip_task_index,
|
prim_info.clip_task_index,
|
||||||
0,
|
0,
|
||||||
render_tasks,
|
render_tasks,
|
||||||
).unwrap_or(OPAQUE_TASK_ADDRESS);
|
).unwrap_or(OPAQUE_TASK_ADDRESS);
|
||||||
|
|
||||||
let prim_header = PrimitiveHeader {
|
let prim_header = PrimitiveHeader {
|
||||||
local_rect: pic.local_rect,
|
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,
|
task_address,
|
||||||
specific_prim_address: GpuCacheAddress::invalid(),
|
specific_prim_address: GpuCacheAddress::invalid(),
|
||||||
clip_task_address,
|
clip_task_address,
|
||||||
|
|
@ -1025,7 +1028,7 @@ impl AlphaBatchBuilder {
|
||||||
|
|
||||||
self.current_batch_list().push_single_instance(
|
self.current_batch_list().push_single_instance(
|
||||||
key,
|
key,
|
||||||
&prim_instance.bounding_rect.as_ref().expect("bug"),
|
&prim_info.clip_chain.pic_clip_rect,
|
||||||
z_id,
|
z_id,
|
||||||
PrimitiveInstanceData::from(instance),
|
PrimitiveInstanceData::from(instance),
|
||||||
);
|
);
|
||||||
|
|
@ -1044,7 +1047,7 @@ impl AlphaBatchBuilder {
|
||||||
PictureCompositeMode::TileCache { .. } => {
|
PictureCompositeMode::TileCache { .. } => {
|
||||||
// Construct a local clip rect that ensures we only draw pixels where
|
// Construct a local clip rect that ensures we only draw pixels where
|
||||||
// the local bounds of the picture extend to within the edge tiles.
|
// 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
|
.combined_local_clip_rect
|
||||||
.intersection(&picture.local_rect)
|
.intersection(&picture.local_rect)
|
||||||
.and_then(|rect| {
|
.and_then(|rect| {
|
||||||
|
|
@ -1503,7 +1506,7 @@ impl AlphaBatchBuilder {
|
||||||
let prim_cache_address = gpu_cache.get_address(&common_data.gpu_cache_handle);
|
let prim_cache_address = gpu_cache.get_address(&common_data.gpu_cache_handle);
|
||||||
let specified_blend_mode = BlendMode::PremultipliedAlpha;
|
let specified_blend_mode = BlendMode::PremultipliedAlpha;
|
||||||
let non_segmented_blend_mode = if !common_data.opacity.is_opaque ||
|
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
|
transform_kind == TransformedRectKind::Complex
|
||||||
{
|
{
|
||||||
specified_blend_mode
|
specified_blend_mode
|
||||||
|
|
@ -1513,7 +1516,7 @@ impl AlphaBatchBuilder {
|
||||||
|
|
||||||
let prim_header = PrimitiveHeader {
|
let prim_header = PrimitiveHeader {
|
||||||
local_rect: prim_rect,
|
local_rect: prim_rect,
|
||||||
local_clip_rect: prim_instance.combined_local_clip_rect,
|
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||||
task_address,
|
task_address,
|
||||||
specific_prim_address: prim_cache_address,
|
specific_prim_address: prim_cache_address,
|
||||||
clip_task_address,
|
clip_task_address,
|
||||||
|
|
@ -1549,7 +1552,7 @@ impl AlphaBatchBuilder {
|
||||||
transform_kind,
|
transform_kind,
|
||||||
render_tasks,
|
render_tasks,
|
||||||
z_id,
|
z_id,
|
||||||
prim_instance.clip_task_index,
|
prim_info.clip_task_index,
|
||||||
ctx,
|
ctx,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -1562,7 +1565,7 @@ impl AlphaBatchBuilder {
|
||||||
let opacity = opacity.combine(prim_data.opacity);
|
let opacity = opacity.combine(prim_data.opacity);
|
||||||
|
|
||||||
let non_segmented_blend_mode = if !opacity.is_opaque ||
|
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
|
transform_kind == TransformedRectKind::Complex
|
||||||
{
|
{
|
||||||
specified_blend_mode
|
specified_blend_mode
|
||||||
|
|
@ -1587,7 +1590,7 @@ impl AlphaBatchBuilder {
|
||||||
|
|
||||||
let prim_header = PrimitiveHeader {
|
let prim_header = PrimitiveHeader {
|
||||||
local_rect: prim_rect,
|
local_rect: prim_rect,
|
||||||
local_clip_rect: prim_instance.combined_local_clip_rect,
|
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||||
task_address,
|
task_address,
|
||||||
specific_prim_address: prim_cache_address,
|
specific_prim_address: prim_cache_address,
|
||||||
clip_task_address,
|
clip_task_address,
|
||||||
|
|
@ -1612,7 +1615,7 @@ impl AlphaBatchBuilder {
|
||||||
transform_kind,
|
transform_kind,
|
||||||
render_tasks,
|
render_tasks,
|
||||||
z_id,
|
z_id,
|
||||||
prim_instance.clip_task_index,
|
prim_info.clip_task_index,
|
||||||
ctx,
|
ctx,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -1676,7 +1679,7 @@ impl AlphaBatchBuilder {
|
||||||
let specified_blend_mode = BlendMode::PremultipliedAlpha;
|
let specified_blend_mode = BlendMode::PremultipliedAlpha;
|
||||||
|
|
||||||
let non_segmented_blend_mode = if !prim_common_data.opacity.is_opaque ||
|
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
|
transform_kind == TransformedRectKind::Complex
|
||||||
{
|
{
|
||||||
specified_blend_mode
|
specified_blend_mode
|
||||||
|
|
@ -1695,7 +1698,7 @@ impl AlphaBatchBuilder {
|
||||||
|
|
||||||
let prim_header = PrimitiveHeader {
|
let prim_header = PrimitiveHeader {
|
||||||
local_rect: prim_rect,
|
local_rect: prim_rect,
|
||||||
local_clip_rect: prim_instance.combined_local_clip_rect,
|
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||||
task_address,
|
task_address,
|
||||||
specific_prim_address: prim_cache_address,
|
specific_prim_address: prim_cache_address,
|
||||||
clip_task_address,
|
clip_task_address,
|
||||||
|
|
@ -1720,7 +1723,7 @@ impl AlphaBatchBuilder {
|
||||||
transform_kind,
|
transform_kind,
|
||||||
render_tasks,
|
render_tasks,
|
||||||
z_id,
|
z_id,
|
||||||
prim_instance.clip_task_index,
|
prim_info.clip_task_index,
|
||||||
ctx,
|
ctx,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -1769,7 +1772,7 @@ impl AlphaBatchBuilder {
|
||||||
let opacity = opacity.combine(common_data.opacity);
|
let opacity = opacity.combine(common_data.opacity);
|
||||||
|
|
||||||
let non_segmented_blend_mode = if !opacity.is_opaque ||
|
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
|
transform_kind == TransformedRectKind::Complex
|
||||||
{
|
{
|
||||||
specified_blend_mode
|
specified_blend_mode
|
||||||
|
|
@ -1799,7 +1802,7 @@ impl AlphaBatchBuilder {
|
||||||
|
|
||||||
let prim_header = PrimitiveHeader {
|
let prim_header = PrimitiveHeader {
|
||||||
local_rect: prim_rect,
|
local_rect: prim_rect,
|
||||||
local_clip_rect: prim_instance.combined_local_clip_rect,
|
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||||
task_address,
|
task_address,
|
||||||
specific_prim_address: prim_cache_address,
|
specific_prim_address: prim_cache_address,
|
||||||
clip_task_address,
|
clip_task_address,
|
||||||
|
|
@ -1824,7 +1827,7 @@ impl AlphaBatchBuilder {
|
||||||
transform_kind,
|
transform_kind,
|
||||||
render_tasks,
|
render_tasks,
|
||||||
z_id,
|
z_id,
|
||||||
prim_instance.clip_task_index,
|
prim_info.clip_task_index,
|
||||||
ctx,
|
ctx,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1869,7 +1872,7 @@ impl AlphaBatchBuilder {
|
||||||
|
|
||||||
let mut prim_header = PrimitiveHeader {
|
let mut prim_header = PrimitiveHeader {
|
||||||
local_rect: prim_rect,
|
local_rect: prim_rect,
|
||||||
local_clip_rect: prim_instance.combined_local_clip_rect,
|
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||||
task_address,
|
task_address,
|
||||||
specific_prim_address: GpuCacheAddress::invalid(),
|
specific_prim_address: GpuCacheAddress::invalid(),
|
||||||
clip_task_address,
|
clip_task_address,
|
||||||
|
|
@ -1878,7 +1881,7 @@ impl AlphaBatchBuilder {
|
||||||
|
|
||||||
if visible_tiles_range.is_empty() {
|
if visible_tiles_range.is_empty() {
|
||||||
let non_segmented_blend_mode = if !prim_data.opacity.is_opaque ||
|
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
|
transform_kind == TransformedRectKind::Complex
|
||||||
{
|
{
|
||||||
specified_blend_mode
|
specified_blend_mode
|
||||||
|
|
@ -1923,7 +1926,7 @@ impl AlphaBatchBuilder {
|
||||||
transform_kind,
|
transform_kind,
|
||||||
render_tasks,
|
render_tasks,
|
||||||
z_id,
|
z_id,
|
||||||
prim_instance.clip_task_index,
|
prim_info.clip_task_index,
|
||||||
ctx,
|
ctx,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1950,7 +1953,7 @@ impl AlphaBatchBuilder {
|
||||||
|
|
||||||
let mut prim_header = PrimitiveHeader {
|
let mut prim_header = PrimitiveHeader {
|
||||||
local_rect: prim_rect,
|
local_rect: prim_rect,
|
||||||
local_clip_rect: prim_instance.combined_local_clip_rect,
|
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||||
task_address,
|
task_address,
|
||||||
specific_prim_address: GpuCacheAddress::invalid(),
|
specific_prim_address: GpuCacheAddress::invalid(),
|
||||||
clip_task_address,
|
clip_task_address,
|
||||||
|
|
@ -1959,7 +1962,7 @@ impl AlphaBatchBuilder {
|
||||||
|
|
||||||
if visible_tiles_range.is_empty() {
|
if visible_tiles_range.is_empty() {
|
||||||
let non_segmented_blend_mode = if !prim_data.opacity.is_opaque ||
|
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
|
transform_kind == TransformedRectKind::Complex
|
||||||
{
|
{
|
||||||
specified_blend_mode
|
specified_blend_mode
|
||||||
|
|
@ -2004,7 +2007,7 @@ impl AlphaBatchBuilder {
|
||||||
transform_kind,
|
transform_kind,
|
||||||
render_tasks,
|
render_tasks,
|
||||||
z_id,
|
z_id,
|
||||||
prim_instance.clip_task_index,
|
prim_info.clip_task_index,
|
||||||
ctx,
|
ctx,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -462,6 +462,21 @@ pub struct ClipChainInstance {
|
||||||
pub pic_clip_rect: PictureRect,
|
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 {
|
impl ClipStore {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
ClipStore {
|
ClipStore {
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,20 @@ pub struct FrameBuilder {
|
||||||
pub config: FrameBuilderConfig,
|
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 struct FrameBuildingContext<'a> {
|
||||||
pub device_pixel_scale: DevicePixelScale,
|
pub device_pixel_scale: DevicePixelScale,
|
||||||
pub scene_properties: &'a SceneProperties,
|
pub scene_properties: &'a SceneProperties,
|
||||||
|
|
@ -198,6 +212,16 @@ impl FrameBuilder {
|
||||||
self.prim_store.destroy(
|
self.prim_store.destroy(
|
||||||
retained_tiles,
|
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
|
/// Compute the contribution (bounding rectangles, and resources) of layers and their
|
||||||
|
|
@ -295,6 +319,30 @@ impl FrameBuilder {
|
||||||
scratch,
|
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 {
|
let mut frame_state = FrameBuildingState {
|
||||||
render_tasks,
|
render_tasks,
|
||||||
profile_counters,
|
profile_counters,
|
||||||
|
|
@ -336,7 +384,6 @@ impl FrameBuilder {
|
||||||
prim_list,
|
prim_list,
|
||||||
pic_context,
|
pic_context,
|
||||||
pic_state,
|
pic_state,
|
||||||
&mut frame_state,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let child_tasks = frame_state
|
let child_tasks = frame_state
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use api::{PicturePixel, RasterPixel, WorldPixel, WorldRect, ImageFormat, ImageDe
|
||||||
#[cfg(feature = "debug_renderer")]
|
#[cfg(feature = "debug_renderer")]
|
||||||
use api::{DebugFlags, DeviceVector2D};
|
use api::{DebugFlags, DeviceVector2D};
|
||||||
use box_shadow::{BLUR_SAMPLE_SCALE};
|
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};
|
use clip_scroll_tree::{ROOT_SPATIAL_NODE_INDEX, ClipScrollTree, SpatialNodeIndex, CoordinateSystemId};
|
||||||
#[cfg(feature = "debug_renderer")]
|
#[cfg(feature = "debug_renderer")]
|
||||||
use debug_colors;
|
use debug_colors;
|
||||||
|
|
@ -24,7 +24,7 @@ use gpu_types::{TransformPalette, TransformPaletteId, UvRectKind};
|
||||||
use plane_split::{Clipper, Polygon, Splitter};
|
use plane_split::{Clipper, Polygon, Splitter};
|
||||||
use prim_store::{PictureIndex, PrimitiveInstance, SpaceMapper, VisibleFace, PrimitiveInstanceKind};
|
use prim_store::{PictureIndex, PrimitiveInstance, SpaceMapper, VisibleFace, PrimitiveInstanceKind};
|
||||||
use prim_store::{get_raster_rects, CoordinateSpaceMapping, PrimitiveScratchBuffer};
|
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 print_tree::PrintTreePrinter;
|
||||||
use render_backend::FrameResources;
|
use render_backend::FrameResources;
|
||||||
use render_task::{ClearMode, RenderTask, RenderTaskCacheEntryHandle, TileBlit};
|
use render_task::{ClearMode, RenderTask, RenderTaskCacheEntryHandle, TileBlit};
|
||||||
|
|
@ -135,6 +135,9 @@ pub struct Tile {
|
||||||
/// The currently visible rect within this tile, updated per frame.
|
/// The currently visible rect within this tile, updated per frame.
|
||||||
/// If None, this tile is not currently visible.
|
/// If None, this tile is not currently visible.
|
||||||
visible_rect: Option<WorldRect>,
|
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
|
/// Uniquely describes the content of this tile, in a way that can be
|
||||||
/// (reasonably) efficiently hashed and compared.
|
/// (reasonably) efficiently hashed and compared.
|
||||||
descriptor: TileDescriptor,
|
descriptor: TileDescriptor,
|
||||||
|
|
@ -155,6 +158,10 @@ pub struct Tile {
|
||||||
/// care about. Stored as a set here, and then collected, sorted
|
/// care about. Stored as a set here, and then collected, sorted
|
||||||
/// and converted to transform key values during post_update.
|
/// and converted to transform key values during post_update.
|
||||||
transforms: FastHashSet<SpatialNodeIndex>,
|
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 {
|
impl Tile {
|
||||||
|
|
@ -166,12 +173,14 @@ impl Tile {
|
||||||
local_rect: LayoutRect::zero(),
|
local_rect: LayoutRect::zero(),
|
||||||
world_rect: WorldRect::zero(),
|
world_rect: WorldRect::zero(),
|
||||||
visible_rect: None,
|
visible_rect: None,
|
||||||
|
valid_rect: WorldRect::zero(),
|
||||||
handle: TextureCacheHandle::invalid(),
|
handle: TextureCacheHandle::invalid(),
|
||||||
descriptor: TileDescriptor::new(),
|
descriptor: TileDescriptor::new(),
|
||||||
is_same_content: false,
|
is_same_content: false,
|
||||||
is_valid: false,
|
is_valid: false,
|
||||||
same_frames: 0,
|
same_frames: 0,
|
||||||
transforms: FastHashSet::default(),
|
transforms: FastHashSet::default(),
|
||||||
|
potential_clips: FastHashMap::default(),
|
||||||
id,
|
id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -180,6 +189,7 @@ impl Tile {
|
||||||
fn clear(&mut self) {
|
fn clear(&mut self) {
|
||||||
self.transforms.clear();
|
self.transforms.clear();
|
||||||
self.descriptor.clear();
|
self.descriptor.clear();
|
||||||
|
self.potential_clips.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update state related to whether a tile has the same
|
/// Update state related to whether a tile has the same
|
||||||
|
|
@ -191,9 +201,9 @@ impl Tile {
|
||||||
|
|
||||||
// The tile is only valid if:
|
// The tile is only valid if:
|
||||||
// - The content is the same *and*
|
// - 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.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.
|
// Update count of how many times this tile has had the same content.
|
||||||
if !self.is_same_content {
|
if !self.is_same_content {
|
||||||
|
|
@ -216,15 +226,6 @@ pub struct PrimitiveDescriptor {
|
||||||
clip_count: u16,
|
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
|
/// Uniquely describes the content of this tile, in a way that can be
|
||||||
/// (reasonably) efficiently hashed and compared.
|
/// (reasonably) efficiently hashed and compared.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -250,12 +251,6 @@ pub struct TileDescriptor {
|
||||||
// TODO(gw): Ugh, get rid of all opacity binding support!
|
// TODO(gw): Ugh, get rid of all opacity binding support!
|
||||||
opacity_bindings: ComparableVec<OpacityBinding>,
|
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
|
/// List of the (quantized) transforms that we care about
|
||||||
/// tracking for this tile.
|
/// tracking for this tile.
|
||||||
transforms: ComparableVec<TransformKey>,
|
transforms: ComparableVec<TransformKey>,
|
||||||
|
|
@ -269,8 +264,6 @@ impl TileDescriptor {
|
||||||
clip_vertices: ComparableVec::new(),
|
clip_vertices: ComparableVec::new(),
|
||||||
opacity_bindings: ComparableVec::new(),
|
opacity_bindings: ComparableVec::new(),
|
||||||
image_keys: ComparableVec::new(),
|
image_keys: ComparableVec::new(),
|
||||||
needed_regions: Vec::new(),
|
|
||||||
current_regions: Vec::new(),
|
|
||||||
transforms: ComparableVec::new(),
|
transforms: ComparableVec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -283,7 +276,6 @@ impl TileDescriptor {
|
||||||
self.clip_vertices.reset();
|
self.clip_vertices.reset();
|
||||||
self.opacity_bindings.reset();
|
self.opacity_bindings.reset();
|
||||||
self.image_keys.reset();
|
self.image_keys.reset();
|
||||||
self.needed_regions.clear();
|
|
||||||
self.transforms.reset();
|
self.transforms.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -298,49 +290,6 @@ impl TileDescriptor {
|
||||||
self.prims.is_valid() &&
|
self.prims.is_valid() &&
|
||||||
self.transforms.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.
|
/// 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 current_clip_chain_id = prim_instance.clip_chain_id;
|
||||||
let mut clip_spatial_nodes = FastHashSet::default();
|
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)
|
// Some primitives can not be cached (e.g. external video images)
|
||||||
let is_cacheable = prim_instance.is_cacheable(
|
let is_cacheable = prim_instance.is_cacheable(
|
||||||
&resources,
|
&resources,
|
||||||
|
|
@ -885,17 +842,27 @@ impl TileCache {
|
||||||
size,
|
size,
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(clip_world_rect) = self.map_local_to_world.map(&local_rect) {
|
match self.map_local_to_world.map(&local_rect) {
|
||||||
// Even if this ends up getting clipped out by the current clip
|
Some(clip_world_rect) => {
|
||||||
// stack, we want to ensure the primitive gets added to the tiles
|
// Even if this ends up getting clipped out by the current clip
|
||||||
// below, to ensure invalidation isn't tripped up by the wrong
|
// stack, we want to ensure the primitive gets added to the tiles
|
||||||
// number of primitives that affect this tile.
|
// below, to ensure invalidation isn't tripped up by the wrong
|
||||||
world_clip_rect = world_clip_rect
|
// number of primitives that affect this tile.
|
||||||
.intersection(&clip_world_rect)
|
world_clip_rect = world_clip_rect
|
||||||
.unwrap_or(WorldRect::zero());
|
.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 {
|
} else {
|
||||||
true
|
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 {
|
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);
|
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
|
// a partially clipped tile, which would be a significant
|
||||||
// optimization for the common case (non-clipped tiles).
|
// 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.
|
// Mark if the tile is cacheable at all.
|
||||||
tile.is_same_content &= is_cacheable;
|
tile.is_same_content &= is_cacheable;
|
||||||
|
|
||||||
|
|
@ -973,6 +930,9 @@ impl TileCache {
|
||||||
for spatial_node_index in &clip_spatial_nodes {
|
for spatial_node_index in &clip_spatial_nodes {
|
||||||
tile.transforms.insert(*spatial_node_index);
|
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.
|
// Step through each tile and invalidate if the dependencies have changed.
|
||||||
for (i, tile) in self.tiles.iter_mut().enumerate() {
|
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
|
// Update tile transforms
|
||||||
let mut transform_spatial_nodes: Vec<SpatialNodeIndex> = tile.transforms.drain().collect();
|
let mut transform_spatial_nodes: Vec<SpatialNodeIndex> = tile.transforms.drain().collect();
|
||||||
transform_spatial_nodes.sort();
|
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 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());
|
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
|
// Store a blit operation to be done after drawing the
|
||||||
// frame in order to update the cached texture tile.
|
// frame in order to update the cached texture tile.
|
||||||
let dest_rect = (valid_rect * frame_context.device_pixel_scale).round().to_i32();
|
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.
|
// We can consider this tile valid now.
|
||||||
tile.is_valid = true;
|
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 {
|
match self.requested_composite_mode {
|
||||||
Some(PictureCompositeMode::Filter(ref filter)) => {
|
Some(PictureCompositeMode::Filter(ref filter)) => {
|
||||||
filter.is_visible()
|
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(
|
let map_pic_to_world = SpaceMapper::new_with_target(
|
||||||
ROOT_SPATIAL_NODE_INDEX,
|
ROOT_SPATIAL_NODE_INDEX,
|
||||||
surface_spatial_node_index,
|
surface_spatial_node_index,
|
||||||
|
|
@ -1902,16 +1870,9 @@ impl PicturePrimitive {
|
||||||
prim_list: PrimitiveList,
|
prim_list: PrimitiveList,
|
||||||
context: PictureContext,
|
context: PictureContext,
|
||||||
state: PictureState,
|
state: PictureState,
|
||||||
frame_state: &mut FrameBuildingState,
|
) {
|
||||||
) -> Option<ClipNodeCollector> {
|
|
||||||
self.prim_list = prim_list;
|
self.prim_list = prim_list;
|
||||||
self.state = Some((state, context));
|
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) {
|
pub fn take_state_and_context(&mut self) -> (PictureState, PictureContext) {
|
||||||
|
|
@ -1926,6 +1887,7 @@ impl PicturePrimitive {
|
||||||
transforms: &TransformPalette,
|
transforms: &TransformPalette,
|
||||||
prim_instance: &PrimitiveInstance,
|
prim_instance: &PrimitiveInstance,
|
||||||
original_local_rect: LayoutRect,
|
original_local_rect: LayoutRect,
|
||||||
|
combined_local_clip_rect: &LayoutRect,
|
||||||
world_rect: WorldRect,
|
world_rect: WorldRect,
|
||||||
plane_split_anchor: usize,
|
plane_split_anchor: usize,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
|
@ -1940,7 +1902,7 @@ impl PicturePrimitive {
|
||||||
// since we determine the UVs by doing a bilerp with a factor
|
// since we determine the UVs by doing a bilerp with a factor
|
||||||
// from the original local rect.
|
// from the original local rect.
|
||||||
let local_rect = match 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(),
|
Some(rect) => rect.cast(),
|
||||||
None => return false,
|
None => return false,
|
||||||
|
|
@ -2298,7 +2260,6 @@ impl PicturePrimitive {
|
||||||
&mut self,
|
&mut self,
|
||||||
pic_index: PictureIndex,
|
pic_index: PictureIndex,
|
||||||
prim_instance: &PrimitiveInstance,
|
prim_instance: &PrimitiveInstance,
|
||||||
prim_local_rect: &LayoutRect,
|
|
||||||
clipped_prim_bounding_rect: WorldRect,
|
clipped_prim_bounding_rect: WorldRect,
|
||||||
surface_index: SurfaceIndex,
|
surface_index: SurfaceIndex,
|
||||||
frame_context: &FrameBuildingContext,
|
frame_context: &FrameBuildingContext,
|
||||||
|
|
@ -2334,7 +2295,7 @@ impl PicturePrimitive {
|
||||||
frame_context.clip_scroll_tree,
|
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(
|
let (clipped, unclipped) = match get_raster_rects(
|
||||||
pic_rect,
|
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)
|
// Basic brush primitive header is (see end of prepare_prim_for_render_inner in prim_store.rs)
|
||||||
// [brush specific data]
|
// [brush specific data]
|
||||||
// [segment_rect, segment data]
|
// [segment_rect, segment data]
|
||||||
let shadow_rect = prim_local_rect.translate(&offset);
|
let shadow_rect = self.local_rect.translate(&offset);
|
||||||
|
|
||||||
// ImageBrush colors
|
// ImageBrush colors
|
||||||
request.push(color.premultiplied());
|
request.push(color.premultiplied());
|
||||||
request.push(PremultipliedColorF::WHITE);
|
request.push(PremultipliedColorF::WHITE);
|
||||||
request.push([
|
request.push([
|
||||||
prim_local_rect.size.width,
|
self.local_rect.size.width,
|
||||||
prim_local_rect.size.height,
|
self.local_rect.size.height,
|
||||||
0.0,
|
0.0,
|
||||||
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) {
|
bool isConstructor) {
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
if (isConstructor) {
|
if (isConstructor) {
|
||||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Array, &proto)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,8 @@ static bool Boolean(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
|
|
||||||
if (args.isConstructing()) {
|
if (args.isConstructing()) {
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Boolean,
|
||||||
|
&proto)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,7 @@ bool DataViewObject::constructSameCompartment(JSContext* cx,
|
||||||
}
|
}
|
||||||
|
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_DataView, &proto)) {
|
||||||
return false;
|
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
|
// Make sure to get the [[Prototype]] for the created view from this
|
||||||
// compartment.
|
// compartment.
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_DataView, &proto)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -651,7 +651,7 @@ bool MapObject::construct(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Map, &proto)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1270,7 +1270,7 @@ bool SetObject::construct(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Set, &proto)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2100,7 +2100,8 @@ static bool PromiseConstructor(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Promise,
|
||||||
|
&proto)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,9 @@ class PromiseObject : public NativeObject {
|
||||||
static JSObject* unforgeableReject(JSContext* cx, HandleValue value);
|
static JSObject* unforgeableReject(JSContext* cx, HandleValue value);
|
||||||
|
|
||||||
int32_t flags() { return getFixedSlot(PromiseSlot_Flags).toInt32(); }
|
int32_t flags() { return getFixedSlot(PromiseSlot_Flags).toInt32(); }
|
||||||
|
void setHandled() {
|
||||||
|
setFixedSlot(PromiseSlot_Flags, Int32Value(flags() | PROMISE_FLAG_HANDLED));
|
||||||
|
}
|
||||||
JS::PromiseState state() {
|
JS::PromiseState state() {
|
||||||
int32_t flags = this->flags();
|
int32_t flags = this->flags();
|
||||||
if (!(flags & PROMISE_FLAG_RESOLVED)) {
|
if (!(flags & PROMISE_FLAG_RESOLVED)) {
|
||||||
|
|
|
||||||
|
|
@ -483,7 +483,7 @@ bool js::regexp_construct(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
|
|
||||||
// Step 7.
|
// Step 7.
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_RegExp, &proto)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -559,7 +559,7 @@ bool js::regexp_construct(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
|
|
||||||
// Step 7.
|
// Step 7.
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_RegExp, &proto)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -313,9 +313,8 @@ class ReadableStreamController : public StreamController {
|
||||||
underlyingSource().toPrivate());
|
underlyingSource().toPrivate());
|
||||||
}
|
}
|
||||||
void setExternalSource(JS::ReadableStreamUnderlyingSource* underlyingSource) {
|
void setExternalSource(JS::ReadableStreamUnderlyingSource* underlyingSource) {
|
||||||
MOZ_ASSERT(getFixedSlot(Slot_Flags).isUndefined());
|
|
||||||
setUnderlyingSource(JS::PrivateValue(underlyingSource));
|
setUnderlyingSource(JS::PrivateValue(underlyingSource));
|
||||||
setFlags(Flag_ExternalSource);
|
addFlags(Flag_ExternalSource);
|
||||||
}
|
}
|
||||||
double strategyHWM() const {
|
double strategyHWM() const {
|
||||||
return getFixedSlot(Slot_StrategyHWM).toNumber();
|
return getFixedSlot(Slot_StrategyHWM).toNumber();
|
||||||
|
|
|
||||||
|
|
@ -3426,7 +3426,7 @@ bool js::StringConstructor(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
|
|
||||||
if (args.isConstructing()) {
|
if (args.isConstructing()) {
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_String, &proto)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -227,7 +227,7 @@ JS_PUBLIC_API bool JS::SetWeakMapEntry(JSContext* cx, HandleObject mapObj,
|
||||||
}
|
}
|
||||||
|
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_WeakMap, &proto)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -172,7 +172,7 @@ bool WeakSetObject::construct(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_WeakSet, &proto)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ static bool Collator(JSContext* cx, const CallArgs& args) {
|
||||||
|
|
||||||
// Steps 2-5 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
|
// Steps 2-5 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Null, &proto)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ static bool DateTimeFormat(JSContext* cx, const CallArgs& args, bool construct,
|
||||||
|
|
||||||
// Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
|
// Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Null, &proto)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ static bool NumberFormat(JSContext* cx, const CallArgs& args, bool construct) {
|
||||||
|
|
||||||
// Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
|
// Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Null, &proto)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ static bool PluralRules(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
|
|
||||||
// Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
|
// Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Null, &proto)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ static bool RelativeTimeFormat(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
|
|
||||||
// Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
|
// Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Null, &proto)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -120,15 +120,14 @@ class UnwinderTypeCache(object):
|
||||||
class_type = gdb.lookup_type('js::jit::' + SizeOfFramePrefix[name])
|
class_type = gdb.lookup_type('js::jit::' + SizeOfFramePrefix[name])
|
||||||
self.frame_class_types[enumval] = class_type.pointer()
|
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():
|
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'
|
mapfile = '/proc/' + str(gdb.selected_inferior().pid) + '/maps'
|
||||||
# Note we only examine executable mappings here.
|
# 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*(.*)$")
|
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)))
|
mappings.append((long(start, 16), long(end, 16)))
|
||||||
return mappings
|
return mappings
|
||||||
|
|
||||||
# A symbol/value pair as expected from gdb frame decorators.
|
|
||||||
|
|
||||||
|
|
||||||
class FrameSymbol(object):
|
class FrameSymbol(object):
|
||||||
|
"A symbol/value pair as expected from gdb frame decorators."
|
||||||
|
|
||||||
def __init__(self, sym, val):
|
def __init__(self, sym, val):
|
||||||
self.sym = sym
|
self.sym = sym
|
||||||
self.val = val
|
self.val = val
|
||||||
|
|
@ -162,12 +161,12 @@ class FrameSymbol(object):
|
||||||
def value(self):
|
def value(self):
|
||||||
return self.val
|
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):
|
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):
|
def __init__(self, base, info, cache):
|
||||||
super(JitFrameDecorator, self).__init__(base)
|
super(JitFrameDecorator, self).__init__(base)
|
||||||
self.info = info
|
self.info = info
|
||||||
|
|
@ -258,10 +257,10 @@ class JitFrameDecorator(FrameDecorator):
|
||||||
result.append(FrameSymbol(name, args_ptr[i]))
|
result.append(FrameSymbol(name, args_ptr[i]))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
# A frame filter for SpiderMonkey.
|
|
||||||
|
|
||||||
|
|
||||||
class SpiderMonkeyFrameFilter(object):
|
class SpiderMonkeyFrameFilter(object):
|
||||||
|
"A frame filter for SpiderMonkey."
|
||||||
|
|
||||||
# |state_holder| is either None, or an instance of
|
# |state_holder| is either None, or an instance of
|
||||||
# SpiderMonkeyUnwinder. If the latter, then this class will
|
# SpiderMonkeyUnwinder. If the latter, then this class will
|
||||||
# reference the |unwinder_state| attribute to find the current
|
# reference the |unwinder_state| attribute to find the current
|
||||||
|
|
@ -285,31 +284,31 @@ class SpiderMonkeyFrameFilter(object):
|
||||||
def filter(self, frame_iter):
|
def filter(self, frame_iter):
|
||||||
return imap(self.maybe_wrap_frame, frame_iter)
|
return imap(self.maybe_wrap_frame, frame_iter)
|
||||||
|
|
||||||
# A frame id class, as specified by the gdb unwinder API.
|
|
||||||
|
|
||||||
|
|
||||||
class SpiderMonkeyFrameId(object):
|
class SpiderMonkeyFrameId(object):
|
||||||
|
"A frame id class, as specified by the gdb unwinder API."
|
||||||
|
|
||||||
def __init__(self, sp, pc):
|
def __init__(self, sp, pc):
|
||||||
self.sp = sp
|
self.sp = sp
|
||||||
self.pc = pc
|
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):
|
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):
|
def __init__(self, typecache):
|
||||||
self.next_sp = None
|
self.next_sp = None
|
||||||
self.next_type = None
|
self.next_type = None
|
||||||
|
|
@ -505,10 +504,10 @@ class UnwinderState(object):
|
||||||
# the time being.
|
# the time being.
|
||||||
return self.unwind_exit_frame(pc, pending_frame)
|
return self.unwind_exit_frame(pc, pending_frame)
|
||||||
|
|
||||||
# The UnwinderState subclass for x86-64.
|
|
||||||
|
|
||||||
|
|
||||||
class x64UnwinderState(UnwinderState):
|
class x64UnwinderState(UnwinderState):
|
||||||
|
"The UnwinderState subclass for x86-64."
|
||||||
|
|
||||||
SP_REGISTER = 'rsp'
|
SP_REGISTER = 'rsp'
|
||||||
PC_REGISTER = 'rip'
|
PC_REGISTER = 'rip'
|
||||||
|
|
||||||
|
|
@ -534,12 +533,12 @@ class x64UnwinderState(UnwinderState):
|
||||||
if reg is "rbp":
|
if reg is "rbp":
|
||||||
unwind_info.add_saved_register(self.SP_REGISTER, sp)
|
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):
|
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|.
|
# A list of all the possible unwinders. See |self.make_unwinder|.
|
||||||
UNWINDERS = [x64UnwinderState]
|
UNWINDERS = [x64UnwinderState]
|
||||||
|
|
||||||
|
|
@ -601,11 +600,11 @@ class SpiderMonkeyUnwinder(Unwinder):
|
||||||
def invalidate_unwinder_state(self, *args, **kwargs):
|
def invalidate_unwinder_state(self, *args, **kwargs):
|
||||||
self.unwinder_state = None
|
self.unwinder_state = None
|
||||||
|
|
||||||
# Register the unwinder and frame filter with |objfile|. If |objfile|
|
|
||||||
# is None, register them globally.
|
|
||||||
|
|
||||||
|
|
||||||
def register_unwinder(objfile):
|
def register_unwinder(objfile):
|
||||||
|
"""Register the unwinder and frame filter with |objfile|. If |objfile|
|
||||||
|
is None, register them globally."""
|
||||||
|
|
||||||
type_cache = UnwinderTypeCache()
|
type_cache = UnwinderTypeCache()
|
||||||
unwinder = None
|
unwinder = None
|
||||||
# This currently only works on Linux, due to parse_proc_maps.
|
# 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());
|
MOZ_ASSERT(args.isConstructing());
|
||||||
|
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Date, &proto)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -388,13 +388,23 @@ JS_PUBLIC_API uint64_t JS::ExceptionTimeWarpTarget(JS::HandleValue value) {
|
||||||
bool Error(JSContext* cx, unsigned argc, Value* vp) {
|
bool Error(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
CallArgs args = CallArgsFromVp(argc, 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
|
// ES6 19.5.1.1 mandates the .prototype lookup happens before the toString
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
if (!GetPrototypeFromBuiltinConstructor(cx, args, protoKey, &proto)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute the error message, if any. */
|
// Compute the error message, if any.
|
||||||
RootedString message(cx, nullptr);
|
RootedString message(cx, nullptr);
|
||||||
if (args.hasDefined(0)) {
|
if (args.hasDefined(0)) {
|
||||||
message = ToString<CanGC>(cx, args[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());
|
NonBuiltinFrameIter iter(cx, cx->realm()->principals());
|
||||||
|
|
||||||
/* Set the 'fileName' property. */
|
|
||||||
RootedString fileName(cx);
|
RootedString fileName(cx);
|
||||||
if (args.length() > 1) {
|
if (args.length() > 1) {
|
||||||
fileName = ToString<CanGC>(cx, args[1]);
|
fileName = ToString<CanGC>(cx, args[1]);
|
||||||
|
|
@ -422,7 +431,6 @@ bool Error(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the 'lineNumber' property. */
|
|
||||||
uint32_t lineNumber, columnNumber = 0;
|
uint32_t lineNumber, columnNumber = 0;
|
||||||
if (args.length() > 2) {
|
if (args.length() > 2) {
|
||||||
if (!ToUint32(cx, args[2], &lineNumber)) {
|
if (!ToUint32(cx, args[2], &lineNumber)) {
|
||||||
|
|
@ -438,15 +446,6 @@ bool Error(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
return false;
|
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,
|
RootedObject obj(cx,
|
||||||
ErrorObject::create(cx, exnType, stack, fileName, lineNumber,
|
ErrorObject::create(cx, exnType, stack, fileName, lineNumber,
|
||||||
columnNumber, nullptr, message, proto));
|
columnNumber, nullptr, message, proto));
|
||||||
|
|
|
||||||
|
|
@ -563,7 +563,7 @@ static bool Number(JSContext* cx, unsigned argc, Value* vp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Number, &proto)) {
|
||||||
return false;
|
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
|
# https://bugzilla.mozilla.org/show_bug.cgi?id=944846
|
||||||
skip script test262/built-ins/Number/prototype/toExponential/return-values.js
|
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
|
# https://bugzilla.mozilla.org/show_bug.cgi?id=1225839
|
||||||
skip script test262/built-ins/Function/internals/Call/class-ctor-realm.js
|
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
|
# 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/arguments-realm.js
|
||||||
skip script test262/built-ins/Proxy/apply/trap-is-not-callable-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/set/trap-is-not-callable-realm.js
|
||||||
skip script test262/built-ins/Proxy/setPrototypeOf/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/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-return-val-realm.js
|
||||||
skip script test262/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js
|
skip script test262/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js
|
||||||
|
|
||||||
# https://bugzilla.mozilla.org/show_bug.cgi?id=1317416
|
# https://bugzilla.mozilla.org/show_bug.cgi?id=1317416
|
||||||
skip script test262/language/expressions/super/realm.js
|
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/GeneratorFunction/proto-from-ctor-realm.js
|
||||||
skip script test262/built-ins/Map/proto-from-ctor-realm.js
|
skip script test262/built-ins/Function/prototype/bind/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
|
|
||||||
|
|
||||||
# https://bugzilla.mozilla.org/show_bug.cgi?id=1317395
|
# https://bugzilla.mozilla.org/show_bug.cgi?id=1317395
|
||||||
skip script test262/built-ins/ArrayBuffer/prototype/byteLength/detached-buffer.js
|
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.')
|
help='Get tests from the given file.')
|
||||||
input_og.add_option('-x', '--exclude-file', action='append',
|
input_og.add_option('-x', '--exclude-file', action='append',
|
||||||
help='Exclude tests from the given file.')
|
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=[],
|
input_og.add_option('--include', action='append', dest='requested_paths', default=[],
|
||||||
help='Include the given test file or directory.')
|
help='Include the given test file or directory.')
|
||||||
input_og.add_option('--exclude', action='append', dest='excluded_paths', default=[],
|
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)
|
test_gen = manifest.load_reftests(test_dir, path_options, xul_tester)
|
||||||
|
|
||||||
# WPT tests are already run in the browser in their own harness.
|
# 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,
|
wpt_tests = load_wpt_tests(xul_tester,
|
||||||
requested_paths,
|
requested_paths,
|
||||||
excluded_paths)
|
excluded_paths)
|
||||||
|
|
|
||||||
|
|
@ -419,7 +419,8 @@ bool ArrayBufferObject::class_constructor(JSContext* cx, unsigned argc,
|
||||||
// Step 3 (Inlined 24.1.1.1 AllocateArrayBuffer).
|
// Step 3 (Inlined 24.1.1.1 AllocateArrayBuffer).
|
||||||
// 24.1.1.1, step 1 (Inlined 9.1.14 OrdinaryCreateFromConstructor).
|
// 24.1.1.1, step 1 (Inlined 9.1.14 OrdinaryCreateFromConstructor).
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_ArrayBuffer,
|
||||||
|
&proto)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -121,12 +121,12 @@ class GlobalObject : public NativeObject {
|
||||||
"global object slot counts are inconsistent");
|
"global object slot counts are inconsistent");
|
||||||
|
|
||||||
static unsigned constructorSlot(JSProtoKey key) {
|
static unsigned constructorSlot(JSProtoKey key) {
|
||||||
MOZ_ASSERT(key <= JSProto_LIMIT);
|
MOZ_ASSERT(key < JSProto_LIMIT);
|
||||||
return APPLICATION_SLOTS + key;
|
return APPLICATION_SLOTS + key;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned prototypeSlot(JSProtoKey key) {
|
static unsigned prototypeSlot(JSProtoKey key) {
|
||||||
MOZ_ASSERT(key <= JSProto_LIMIT);
|
MOZ_ASSERT(key < JSProto_LIMIT);
|
||||||
return APPLICATION_SLOTS + JSProto_LIMIT + key;
|
return APPLICATION_SLOTS + JSProto_LIMIT + key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -357,7 +357,7 @@ class MOZ_STACK_CLASS TryNoteIter {
|
||||||
} while (!(pcInRange() && tn_->kind == JSTRY_FOR_OF));
|
} while (!(pcInRange() && tn_->kind == JSTRY_FOR_OF));
|
||||||
|
|
||||||
// Advance to trynote following the enclosing 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JSProtoKey protoKey = JSProto_Null;
|
||||||
if (isAsync) {
|
if (isAsync) {
|
||||||
if (isGenerator) {
|
if (isGenerator) {
|
||||||
if (!CompileStandaloneAsyncGenerator(cx, &fun, options, srcBuf,
|
if (!CompileStandaloneAsyncGenerator(cx, &fun, options, srcBuf,
|
||||||
|
|
@ -2022,12 +2023,13 @@ static bool CreateDynamicFunction(JSContext* cx, const CallArgs& args,
|
||||||
parameterListEnd)) {
|
parameterListEnd)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
protoKey = JSProto_Function;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Steps 6, 29.
|
// Steps 6, 29.
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
if (!GetPrototypeFromBuiltinConstructor(cx, args, protoKey, &proto)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1026,7 +1026,8 @@ bool js::NewObjectScriptedCall(JSContext* cx, MutableHandleObject pobj) {
|
||||||
JSObject* js::CreateThis(JSContext* cx, const Class* newclasp,
|
JSObject* js::CreateThis(JSContext* cx, const Class* newclasp,
|
||||||
HandleObject callee) {
|
HandleObject callee) {
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
if (!GetPrototypeFromConstructor(cx, callee, &proto)) {
|
if (!GetPrototypeFromConstructor(
|
||||||
|
cx, callee, JSCLASS_CACHED_PROTO_KEY(newclasp), &proto)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
gc::AllocKind kind = NewObjectGCKind(newclasp);
|
gc::AllocKind kind = NewObjectGCKind(newclasp);
|
||||||
|
|
@ -1158,12 +1159,45 @@ JSObject* js::CreateThisForFunctionWithProto(
|
||||||
}
|
}
|
||||||
|
|
||||||
bool js::GetPrototypeFromConstructor(JSContext* cx, HandleObject newTarget,
|
bool js::GetPrototypeFromConstructor(JSContext* cx, HandleObject newTarget,
|
||||||
|
JSProtoKey intrinsicDefaultProto,
|
||||||
MutableHandleObject proto) {
|
MutableHandleObject proto) {
|
||||||
RootedValue protov(cx);
|
RootedValue protov(cx);
|
||||||
if (!GetProperty(cx, newTarget, newTarget, cx->names().prototype, &protov)) {
|
if (!GetProperty(cx, newTarget, newTarget, cx->names().prototype, &protov)) {
|
||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1171,7 +1205,7 @@ JSObject* js::CreateThisForFunction(JSContext* cx, HandleObject callee,
|
||||||
HandleObject newTarget,
|
HandleObject newTarget,
|
||||||
NewObjectKind newKind) {
|
NewObjectKind newKind) {
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) {
|
if (!GetPrototypeFromConstructor(cx, newTarget, JSProto_Null, &proto)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3679,6 +3713,10 @@ static void DumpProperty(const NativeObject* obj, Shape& shape,
|
||||||
out.printf(")\n");
|
out.printf(")\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool JSObject::hasSameRealmAs(JSContext* cx) const {
|
||||||
|
return nonCCWRealm() == cx->realm();
|
||||||
|
}
|
||||||
|
|
||||||
bool JSObject::uninlinedIsProxy() const { return is<ProxyObject>(); }
|
bool JSObject::uninlinedIsProxy() const { return is<ProxyObject>(); }
|
||||||
|
|
||||||
bool JSObject::uninlinedNonProxyIsExtensible() const {
|
bool JSObject::uninlinedNonProxyIsExtensible() const {
|
||||||
|
|
|
||||||
|
|
@ -435,6 +435,7 @@ class JSObject : public js::gc::Cell {
|
||||||
MOZ_ASSERT(!js::UninlinedIsCrossCompartmentWrapper(this));
|
MOZ_ASSERT(!js::UninlinedIsCrossCompartmentWrapper(this));
|
||||||
return group_->realm();
|
return group_->realm();
|
||||||
}
|
}
|
||||||
|
bool hasSameRealmAs(JSContext* cx) const;
|
||||||
|
|
||||||
// Returns the object's realm even if the object is a CCW (be careful, in
|
// 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
|
// 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.
|
// ES6 9.1.15 GetPrototypeFromConstructor.
|
||||||
extern bool GetPrototypeFromConstructor(JSContext* cx,
|
extern bool GetPrototypeFromConstructor(JSContext* cx,
|
||||||
js::HandleObject newTarget,
|
js::HandleObject newTarget,
|
||||||
|
JSProtoKey intrinsicDefaultProto,
|
||||||
js::MutableHandleObject proto);
|
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(
|
MOZ_ALWAYS_INLINE bool GetPrototypeFromBuiltinConstructor(
|
||||||
JSContext* cx, const CallArgs& args, js::MutableHandleObject proto) {
|
JSContext* cx, const CallArgs& args, JSProtoKey intrinsicDefaultProto,
|
||||||
// When proto is set to nullptr, the caller is expected to select the
|
js::MutableHandleObject proto) {
|
||||||
// correct default built-in prototype for this constructor.
|
// 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() ||
|
if (!args.isConstructing() ||
|
||||||
&args.newTarget().toObject() == &args.callee()) {
|
&args.newTarget().toObject() == &args.callee()) {
|
||||||
|
MOZ_ASSERT(args.callee().hasSameRealmAs(cx));
|
||||||
proto.set(nullptr);
|
proto.set(nullptr);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -808,7 +830,8 @@ MOZ_ALWAYS_INLINE bool GetPrototypeFromBuiltinConstructor(
|
||||||
// We're calling this constructor from a derived class, retrieve the
|
// We're calling this constructor from a derived class, retrieve the
|
||||||
// actual prototype from newTarget.
|
// actual prototype from newTarget.
|
||||||
RootedObject newTarget(cx, &args.newTarget().toObject());
|
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,
|
// 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).
|
// Step 3 (Inlined 24.2.1.1 AllocateSharedArrayBuffer).
|
||||||
// 24.2.1.1, step 1 (Inlined 9.1.14 OrdinaryCreateFromConstructor).
|
// 24.2.1.1, step 1 (Inlined 9.1.14 OrdinaryCreateFromConstructor).
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_SharedArrayBuffer,
|
||||||
|
&proto)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -121,38 +121,47 @@ struct TypeIDOfType;
|
||||||
template <>
|
template <>
|
||||||
struct TypeIDOfType<int8_t> {
|
struct TypeIDOfType<int8_t> {
|
||||||
static const Scalar::Type id = Scalar::Int8;
|
static const Scalar::Type id = Scalar::Int8;
|
||||||
|
static const JSProtoKey protoKey = JSProto_Int8Array;
|
||||||
};
|
};
|
||||||
template <>
|
template <>
|
||||||
struct TypeIDOfType<uint8_t> {
|
struct TypeIDOfType<uint8_t> {
|
||||||
static const Scalar::Type id = Scalar::Uint8;
|
static const Scalar::Type id = Scalar::Uint8;
|
||||||
|
static const JSProtoKey protoKey = JSProto_Uint8Array;
|
||||||
};
|
};
|
||||||
template <>
|
template <>
|
||||||
struct TypeIDOfType<int16_t> {
|
struct TypeIDOfType<int16_t> {
|
||||||
static const Scalar::Type id = Scalar::Int16;
|
static const Scalar::Type id = Scalar::Int16;
|
||||||
|
static const JSProtoKey protoKey = JSProto_Int16Array;
|
||||||
};
|
};
|
||||||
template <>
|
template <>
|
||||||
struct TypeIDOfType<uint16_t> {
|
struct TypeIDOfType<uint16_t> {
|
||||||
static const Scalar::Type id = Scalar::Uint16;
|
static const Scalar::Type id = Scalar::Uint16;
|
||||||
|
static const JSProtoKey protoKey = JSProto_Uint16Array;
|
||||||
};
|
};
|
||||||
template <>
|
template <>
|
||||||
struct TypeIDOfType<int32_t> {
|
struct TypeIDOfType<int32_t> {
|
||||||
static const Scalar::Type id = Scalar::Int32;
|
static const Scalar::Type id = Scalar::Int32;
|
||||||
|
static const JSProtoKey protoKey = JSProto_Int32Array;
|
||||||
};
|
};
|
||||||
template <>
|
template <>
|
||||||
struct TypeIDOfType<uint32_t> {
|
struct TypeIDOfType<uint32_t> {
|
||||||
static const Scalar::Type id = Scalar::Uint32;
|
static const Scalar::Type id = Scalar::Uint32;
|
||||||
|
static const JSProtoKey protoKey = JSProto_Uint32Array;
|
||||||
};
|
};
|
||||||
template <>
|
template <>
|
||||||
struct TypeIDOfType<float> {
|
struct TypeIDOfType<float> {
|
||||||
static const Scalar::Type id = Scalar::Float32;
|
static const Scalar::Type id = Scalar::Float32;
|
||||||
|
static const JSProtoKey protoKey = JSProto_Float32Array;
|
||||||
};
|
};
|
||||||
template <>
|
template <>
|
||||||
struct TypeIDOfType<double> {
|
struct TypeIDOfType<double> {
|
||||||
static const Scalar::Type id = Scalar::Float64;
|
static const Scalar::Type id = Scalar::Float64;
|
||||||
|
static const JSProtoKey protoKey = JSProto_Float64Array;
|
||||||
};
|
};
|
||||||
template <>
|
template <>
|
||||||
struct TypeIDOfType<uint8_clamped> {
|
struct TypeIDOfType<uint8_clamped> {
|
||||||
static const Scalar::Type id = Scalar::Uint8Clamped;
|
static const Scalar::Type id = Scalar::Uint8Clamped;
|
||||||
|
static const JSProtoKey protoKey = JSProto_Uint8ClampedArray;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SharedOps {
|
class SharedOps {
|
||||||
|
|
|
||||||
|
|
@ -285,6 +285,10 @@ class TypedArrayObjectTemplate : public TypedArrayObject {
|
||||||
static constexpr Scalar::Type ArrayTypeID() {
|
static constexpr Scalar::Type ArrayTypeID() {
|
||||||
return TypeIDOfType<NativeType>::id;
|
return TypeIDOfType<NativeType>::id;
|
||||||
}
|
}
|
||||||
|
static constexpr JSProtoKey protoKey() {
|
||||||
|
return TypeIDOfType<NativeType>::protoKey;
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr bool ArrayTypeIsUnsigned() {
|
static constexpr bool ArrayTypeIsUnsigned() {
|
||||||
return TypeIsUnsigned<NativeType>();
|
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.1, step 3 and 22.2.4.2, step 5.
|
||||||
// 22.2.4.2.1 AllocateTypedArray, step 1.
|
// 22.2.4.2.1 AllocateTypedArray, step 1.
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
if (!GetPrototypeFromBuiltinConstructor(cx, args, protoKey(), &proto)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -608,7 +612,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject {
|
||||||
// 22.2.4.{3,4,5}, step 4.
|
// 22.2.4.{3,4,5}, step 4.
|
||||||
// 22.2.4.2.1 AllocateTypedArray, step 1.
|
// 22.2.4.2.1 AllocateTypedArray, step 1.
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) {
|
if (!GetPrototypeFromBuiltinConstructor(cx, args, protoKey(), &proto)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -957,20 +961,9 @@ template <typename T>
|
||||||
// As an optimization, skip the "prototype" lookup for %ArrayBuffer%.
|
// As an optimization, skip the "prototype" lookup for %ArrayBuffer%.
|
||||||
if (ctor != arrayBufferCtor) {
|
if (ctor != arrayBufferCtor) {
|
||||||
// 9.1.13 OrdinaryCreateFromConstructor, steps 1-2.
|
// 9.1.13 OrdinaryCreateFromConstructor, steps 1-2.
|
||||||
if (!GetPrototypeFromConstructor(cx, ctor, &proto)) {
|
if (!GetPrototypeFromConstructor(cx, ctor, JSProto_ArrayBuffer, &proto)) {
|
||||||
return false;
|
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.
|
// 24.1.1.1 steps 1 (remaining part), 2-6.
|
||||||
|
|
|
||||||
|
|
@ -2557,7 +2557,6 @@ static void WrapSeparatorTransform(nsDisplayListBuilder* aBuilder,
|
||||||
nsDisplayTransform* item = MakeDisplayItem<nsDisplayTransform>(
|
nsDisplayTransform* item = MakeDisplayItem<nsDisplayTransform>(
|
||||||
aBuilder, aFrame, aNonParticipants, aBuilder->GetVisibleRect(),
|
aBuilder, aFrame, aNonParticipants, aBuilder->GetVisibleRect(),
|
||||||
Matrix4x4(), aIndex);
|
Matrix4x4(), aIndex);
|
||||||
item->SetNoExtendContext();
|
|
||||||
|
|
||||||
if (*aSeparator == nullptr) {
|
if (*aSeparator == nullptr) {
|
||||||
*aSeparator = item;
|
*aSeparator = item;
|
||||||
|
|
|
||||||
|
|
@ -7184,7 +7184,6 @@ nsDisplayTransform::nsDisplayTransform(
|
||||||
mAnimatedGeometryRootForScrollMetadata(mAnimatedGeometryRoot),
|
mAnimatedGeometryRootForScrollMetadata(mAnimatedGeometryRoot),
|
||||||
mChildrenBuildingRect(aChildrenBuildingRect),
|
mChildrenBuildingRect(aChildrenBuildingRect),
|
||||||
mIndex(aIndex),
|
mIndex(aIndex),
|
||||||
mNoExtendContext(false),
|
|
||||||
mIsTransformSeparator(false),
|
mIsTransformSeparator(false),
|
||||||
mTransformPreserves3DInited(false),
|
mTransformPreserves3DInited(false),
|
||||||
mAllowAsyncAnimation(false) {
|
mAllowAsyncAnimation(false) {
|
||||||
|
|
@ -7248,7 +7247,6 @@ nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
|
||||||
mAnimatedGeometryRootForScrollMetadata(mAnimatedGeometryRoot),
|
mAnimatedGeometryRootForScrollMetadata(mAnimatedGeometryRoot),
|
||||||
mChildrenBuildingRect(aChildrenBuildingRect),
|
mChildrenBuildingRect(aChildrenBuildingRect),
|
||||||
mIndex(aIndex),
|
mIndex(aIndex),
|
||||||
mNoExtendContext(false),
|
|
||||||
mIsTransformSeparator(false),
|
mIsTransformSeparator(false),
|
||||||
mTransformPreserves3DInited(false),
|
mTransformPreserves3DInited(false),
|
||||||
mAllowAsyncAnimation(aAllowAsyncAnimation) {
|
mAllowAsyncAnimation(aAllowAsyncAnimation) {
|
||||||
|
|
@ -7272,7 +7270,6 @@ nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
|
||||||
mAnimatedGeometryRootForScrollMetadata(mAnimatedGeometryRoot),
|
mAnimatedGeometryRootForScrollMetadata(mAnimatedGeometryRoot),
|
||||||
mChildrenBuildingRect(aChildrenBuildingRect),
|
mChildrenBuildingRect(aChildrenBuildingRect),
|
||||||
mIndex(aIndex),
|
mIndex(aIndex),
|
||||||
mNoExtendContext(false),
|
|
||||||
mIsTransformSeparator(true),
|
mIsTransformSeparator(true),
|
||||||
mTransformPreserves3DInited(false),
|
mTransformPreserves3DInited(false),
|
||||||
mAllowAsyncAnimation(false) {
|
mAllowAsyncAnimation(false) {
|
||||||
|
|
@ -7873,13 +7870,15 @@ bool nsDisplayTransform::CreateWebRenderCommands(
|
||||||
bool animated =
|
bool animated =
|
||||||
ActiveLayerTracker::IsStyleMaybeAnimated(Frame(), eCSSProperty_transform);
|
ActiveLayerTracker::IsStyleMaybeAnimated(Frame(), eCSSProperty_transform);
|
||||||
|
|
||||||
|
bool preserve3D = mFrame->Extend3DContext() && !mIsTransformSeparator;
|
||||||
|
|
||||||
StackingContextHelper sc(
|
StackingContextHelper sc(
|
||||||
aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder, filters,
|
aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder, filters,
|
||||||
LayoutDeviceRect(position, LayoutDeviceSize()), &newTransformMatrix,
|
LayoutDeviceRect(position, LayoutDeviceSize()), &newTransformMatrix,
|
||||||
animationsId ? &prop : nullptr, nullptr, transformForSC, nullptr,
|
animationsId ? &prop : nullptr, nullptr, transformForSC, nullptr,
|
||||||
gfx::CompositionOp::OP_OVER, !BackfaceIsHidden(),
|
gfx::CompositionOp::OP_OVER, !BackfaceIsHidden(),
|
||||||
mFrame->Extend3DContext() && !mNoExtendContext, deferredTransformItem,
|
preserve3D, deferredTransformItem, wr::WrStackingContextClip::None(),
|
||||||
wr::WrStackingContextClip::None(), animated);
|
animated);
|
||||||
|
|
||||||
return mStoredList.CreateWebRenderCommands(aBuilder, aResources, sc, aManager,
|
return mStoredList.CreateWebRenderCommands(aBuilder, aResources, sc, aManager,
|
||||||
aDisplayListBuilder);
|
aDisplayListBuilder);
|
||||||
|
|
@ -7932,8 +7931,8 @@ already_AddRefed<Layer> nsDisplayTransform::BuildLayer(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the preserve-3d flag for this layer, BuildContainerLayerFor clears all
|
// Add the preserve-3d flag for this layer, BuildContainerLayerFor clears all
|
||||||
// flags, so we never need to explicitely unset this flag.
|
// flags, so we never need to explicitly unset this flag.
|
||||||
if (mFrame->Extend3DContext() && !mNoExtendContext) {
|
if (mFrame->Extend3DContext() && !mIsTransformSeparator) {
|
||||||
container->SetContentFlags(container->GetContentFlags() |
|
container->SetContentFlags(container->GetContentFlags() |
|
||||||
Layer::CONTENT_EXTEND_3D_CONTEXT);
|
Layer::CONTENT_EXTEND_3D_CONTEXT);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -6710,10 +6710,6 @@ class nsDisplayTransform : public nsDisplayHitTestInfoItem {
|
||||||
|
|
||||||
void WriteDebugInfo(std::stringstream& aStream) override;
|
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 {
|
void DoUpdateBoundsPreserves3D(nsDisplayListBuilder* aBuilder) override {
|
||||||
MOZ_ASSERT(mFrame->Combines3DTransformWithAncestors() ||
|
MOZ_ASSERT(mFrame->Combines3DTransformWithAncestors() ||
|
||||||
IsTransformSeparator());
|
IsTransformSeparator());
|
||||||
|
|
@ -6794,15 +6790,13 @@ class nsDisplayTransform : public nsDisplayHitTestInfoItem {
|
||||||
mutable nsRect mBounds;
|
mutable nsRect mBounds;
|
||||||
// True for mBounds is valid.
|
// True for mBounds is valid.
|
||||||
mutable bool mHasBounds;
|
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
|
// This item is a separator between 3D rendering contexts, and
|
||||||
// mTransform have been presetted by the constructor.
|
// 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;
|
bool mIsTransformSeparator;
|
||||||
// True if mTransformPreserves3D have been initialized.
|
// True if mTransformPreserves3D have been initialized.
|
||||||
bool mTransformPreserves3DInited;
|
bool mTransformPreserves3DInited;
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.os.Parcelable;
|
||||||
import android.os.StrictMode;
|
import android.os.StrictMode;
|
||||||
import android.provider.ContactsContract;
|
import android.provider.ContactsContract;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
@ -71,6 +72,7 @@ import android.support.design.widget.Snackbar;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.SparseArray;
|
||||||
import android.util.SparseBooleanArray;
|
import android.util.SparseBooleanArray;
|
||||||
import android.util.SparseIntArray;
|
import android.util.SparseIntArray;
|
||||||
import android.view.KeyEvent;
|
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";
|
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 EXTRA_STATE_BUNDLE = "stateBundle";
|
||||||
|
|
||||||
public static final String PREFS_ALLOW_STATE_BUNDLE = "allowStateBundle";
|
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());
|
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) { }
|
public void addTab(int flags) { }
|
||||||
|
|
@ -696,7 +709,7 @@ public abstract class GeckoApp extends GeckoActivity
|
||||||
rec.recordGeckoStartupTime(mGeckoReadyStartupTimer.getElapsed());
|
rec.recordGeckoStartupTime(mGeckoReadyStartupTimer.getElapsed());
|
||||||
}
|
}
|
||||||
|
|
||||||
((GeckoApplication) getApplicationContext()).onDelayedStartup();
|
getGeckoApplication().onDelayedStartup();
|
||||||
|
|
||||||
// Reset the crash loop counter if we remain alive for at least half a minute.
|
// Reset the crash loop counter if we remain alive for at least half a minute.
|
||||||
ThreadUtils.postDelayedToBackgroundThread(new Runnable() {
|
ThreadUtils.postDelayedToBackgroundThread(new Runnable() {
|
||||||
|
|
@ -976,6 +989,11 @@ public abstract class GeckoApp extends GeckoActivity
|
||||||
**/
|
**/
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
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).
|
// Enable Android Strict Mode for developers' local builds (the "default" channel).
|
||||||
if ("default".equals(AppConstants.MOZ_UPDATE_CHANNEL)) {
|
if ("default".equals(AppConstants.MOZ_UPDATE_CHANNEL)) {
|
||||||
enableStrictMode();
|
enableStrictMode();
|
||||||
|
|
@ -1106,6 +1124,9 @@ public abstract class GeckoApp extends GeckoActivity
|
||||||
mGeckoLayout = (RelativeLayout) findViewById(R.id.gecko_layout);
|
mGeckoLayout = (RelativeLayout) findViewById(R.id.gecko_layout);
|
||||||
mMainLayout = (RelativeLayout) findViewById(R.id.main_layout);
|
mMainLayout = (RelativeLayout) findViewById(R.id.main_layout);
|
||||||
mLayerView = (GeckoView) findViewById(R.id.layer_view);
|
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(
|
final GeckoSession session = new GeckoSession(
|
||||||
new GeckoSessionSettings.Builder()
|
new GeckoSessionSettings.Builder()
|
||||||
|
|
@ -1119,6 +1140,9 @@ public abstract class GeckoApp extends GeckoActivity
|
||||||
}
|
}
|
||||||
mLayerView.setSession(session, GeckoApplication.getRuntime());
|
mLayerView.setSession(session, GeckoApplication.getRuntime());
|
||||||
mLayerView.setOverScrollMode(View.OVER_SCROLL_NEVER);
|
mLayerView.setOverScrollMode(View.OVER_SCROLL_NEVER);
|
||||||
|
if (mIsRestoringActivity && !receivedSavedInstanceState) {
|
||||||
|
restoreGeckoViewState(getGeckoApplication().getSavedState());
|
||||||
|
}
|
||||||
|
|
||||||
getAppEventDispatcher().registerGeckoThreadListener(this,
|
getAppEventDispatcher().registerGeckoThreadListener(this,
|
||||||
"Locale:Set",
|
"Locale:Set",
|
||||||
|
|
@ -1313,6 +1337,26 @@ public abstract class GeckoApp extends GeckoActivity
|
||||||
mWasFirstTabShownAfterActivityUnhidden = false; // onStart indicates we were hidden.
|
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
|
@Override
|
||||||
protected void onStop() {
|
protected void onStop() {
|
||||||
super.onStop();
|
super.onStop();
|
||||||
|
|
@ -2534,6 +2578,10 @@ public abstract class GeckoApp extends GeckoActivity
|
||||||
return mLayerView;
|
return mLayerView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected GeckoApplication getGeckoApplication() {
|
||||||
|
return (GeckoApplication) getApplicationContext();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setRequestedOrientationForCurrentActivity(int requestedActivityInfoOrientation) {
|
public boolean setRequestedOrientationForCurrentActivity(int requestedActivityInfoOrientation) {
|
||||||
// We want to support the Screen Orientation API, and it always makes sense to lock the
|
// 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.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
|
import android.os.Parcelable;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.provider.MediaStore;
|
import android.provider.MediaStore;
|
||||||
|
|
@ -26,6 +27,7 @@ import android.support.multidex.MultiDex;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
|
||||||
import com.squareup.leakcanary.LeakCanary;
|
import com.squareup.leakcanary.LeakCanary;
|
||||||
import com.squareup.leakcanary.RefWatcher;
|
import com.squareup.leakcanary.RefWatcher;
|
||||||
|
|
@ -81,6 +83,10 @@ public class GeckoApplication extends Application
|
||||||
|
|
||||||
private LightweightTheme mLightweightTheme;
|
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 RefWatcher mRefWatcher;
|
||||||
|
|
||||||
private final EventListener mListener = new EventListener();
|
private final EventListener mListener = new EventListener();
|
||||||
|
|
@ -641,6 +647,14 @@ public class GeckoApplication extends Application
|
||||||
mLightweightTheme = new LightweightTheme(this);
|
mLightweightTheme = new LightweightTheme(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* package */ void setSavedState(SparseArray<Parcelable> savedState) {
|
||||||
|
mSavedState = savedState;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* package */ SparseArray<Parcelable> getSavedState() {
|
||||||
|
return mSavedState;
|
||||||
|
}
|
||||||
|
|
||||||
public static void createShortcut() {
|
public static void createShortcut() {
|
||||||
final Tab selectedTab = Tabs.getInstance().getSelectedTab();
|
final Tab selectedTab = Tabs.getInstance().getSelectedTab();
|
||||||
if (selectedTab != null) {
|
if (selectedTab != null) {
|
||||||
|
|
|
||||||
|
|
@ -201,6 +201,8 @@ public class UpdateServiceHelper {
|
||||||
.replace("%DISTRIBUTION_VERSION%", "default")
|
.replace("%DISTRIBUTION_VERSION%", "default")
|
||||||
.replace("%MOZ_VERSION%", AppConstants.MOZILLA_VERSION);
|
.replace("%MOZ_VERSION%", AppConstants.MOZILLA_VERSION);
|
||||||
|
|
||||||
|
Log.i(LOGTAG, "AUS Url is: " + url);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return new URI(url);
|
return new URI(url);
|
||||||
} catch (java.net.URISyntaxException e) {
|
} catch (java.net.URISyntaxException e) {
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,7 @@ class AccessibilityTest : BaseSessionTest() {
|
||||||
|
|
||||||
private interface EventDelegate {
|
private interface EventDelegate {
|
||||||
fun onAccessibilityFocused(event: AccessibilityEvent) { }
|
fun onAccessibilityFocused(event: AccessibilityEvent) { }
|
||||||
|
fun onAccessibilityFocusCleared(event: AccessibilityEvent) { }
|
||||||
fun onClicked(event: AccessibilityEvent) { }
|
fun onClicked(event: AccessibilityEvent) { }
|
||||||
fun onFocused(event: AccessibilityEvent) { }
|
fun onFocused(event: AccessibilityEvent) { }
|
||||||
fun onSelected(event: AccessibilityEvent) { }
|
fun onSelected(event: AccessibilityEvent) { }
|
||||||
|
|
@ -125,6 +126,7 @@ class AccessibilityTest : BaseSessionTest() {
|
||||||
AccessibilityEvent.TYPE_VIEW_FOCUSED -> newDelegate.onFocused(event)
|
AccessibilityEvent.TYPE_VIEW_FOCUSED -> newDelegate.onFocused(event)
|
||||||
AccessibilityEvent.TYPE_VIEW_CLICKED -> newDelegate.onClicked(event)
|
AccessibilityEvent.TYPE_VIEW_CLICKED -> newDelegate.onClicked(event)
|
||||||
AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED -> newDelegate.onAccessibilityFocused(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_SELECTED -> newDelegate.onSelected(event)
|
||||||
AccessibilityEvent.TYPE_VIEW_SCROLLED -> newDelegate.onScrolled(event)
|
AccessibilityEvent.TYPE_VIEW_SCROLLED -> newDelegate.onScrolled(event)
|
||||||
AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED -> newDelegate.onTextSelectionChanged(event)
|
AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED -> newDelegate.onTextSelectionChanged(event)
|
||||||
|
|
@ -192,6 +194,7 @@ class AccessibilityTest : BaseSessionTest() {
|
||||||
assertThat("Label accessibility focused", node.className.toString(),
|
assertThat("Label accessibility focused", node.className.toString(),
|
||||||
equalTo("android.view.View"))
|
equalTo("android.view.View"))
|
||||||
assertThat("Text node should not be focusable", node.isFocusable, equalTo(false))
|
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))
|
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(),
|
assertThat("Editbox accessibility focused", node.className.toString(),
|
||||||
equalTo("android.widget.EditText"))
|
equalTo("android.widget.EditText"))
|
||||||
assertThat("Entry node should be focusable", node.isFocusable, equalTo(true))
|
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))
|
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() {
|
@Test fun testTextEntryNode() {
|
||||||
|
|
|
||||||
|
|
@ -118,10 +118,6 @@ public class SessionAccessibility {
|
||||||
if (mAttached) {
|
if (mAttached) {
|
||||||
node = mSession.getSettings().getFullAccessibilityTree() ?
|
node = mSession.getSettings().getFullAccessibilityTree() ?
|
||||||
getNodeFromGecko(virtualDescendantId) : getNodeFromCache(virtualDescendantId);
|
getNodeFromGecko(virtualDescendantId) : getNodeFromCache(virtualDescendantId);
|
||||||
if (node != null) {
|
|
||||||
node.setAccessibilityFocused(mAccessibilityFocusedNode == virtualDescendantId);
|
|
||||||
node.setFocused(mFocusedNode == virtualDescendantId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node == null) {
|
if (node == null) {
|
||||||
|
|
@ -143,6 +139,9 @@ public class SessionAccessibility {
|
||||||
final GeckoBundle data;
|
final GeckoBundle data;
|
||||||
|
|
||||||
switch (action) {
|
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:
|
case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS:
|
||||||
if (virtualViewId == View.NO_ID) {
|
if (virtualViewId == View.NO_ID) {
|
||||||
sendEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED, View.NO_ID, CLASSNAME_WEBVIEW, null);
|
sendEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED, View.NO_ID, CLASSNAME_WEBVIEW, null);
|
||||||
|
|
@ -296,7 +295,8 @@ public class SessionAccessibility {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isRoot = nodeInfo.getInt("id") == View.NO_ID;
|
final int id = nodeInfo.getInt("id");
|
||||||
|
boolean isRoot = id == View.NO_ID;
|
||||||
if (isRoot) {
|
if (isRoot) {
|
||||||
if (Build.VERSION.SDK_INT < 17 || mView.getDisplay() != null) {
|
if (Build.VERSION.SDK_INT < 17 || mView.getDisplay() != null) {
|
||||||
// When running junit tests we don't have a display
|
// When running junit tests we don't have a display
|
||||||
|
|
@ -321,8 +321,6 @@ public class SessionAccessibility {
|
||||||
// Add actions
|
// Add actions
|
||||||
node.addAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT);
|
node.addAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT);
|
||||||
node.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_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_PREVIOUS_AT_MOVEMENT_GRANULARITY);
|
||||||
node.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY);
|
node.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY);
|
||||||
node.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER |
|
node.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER |
|
||||||
|
|
@ -348,6 +346,14 @@ public class SessionAccessibility {
|
||||||
// Other boolean properties to consider later:
|
// Other boolean properties to consider later:
|
||||||
// setHeading, setImportantForAccessibility, setScreenReaderFocusable, setShowingHintText, setDismissable
|
// 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
|
// Bounds
|
||||||
int[] b = nodeInfo.getIntArray("bounds");
|
int[] b = nodeInfo.getIntArray("bounds");
|
||||||
if (b != null) {
|
if (b != null) {
|
||||||
|
|
@ -714,6 +720,11 @@ public class SessionAccessibility {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED:
|
||||||
|
if (mAccessibilityFocusedNode == sourceId) {
|
||||||
|
mAccessibilityFocusedNode = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED:
|
case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED:
|
||||||
mAccessibilityFocusedNode = sourceId;
|
mAccessibilityFocusedNode = sourceId;
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -5334,7 +5334,11 @@ pref("dom.vr.autoactivate.enabled", false);
|
||||||
// The threshold value of trigger inputs for VR controllers
|
// The threshold value of trigger inputs for VR controllers
|
||||||
pref("dom.vr.controller_trigger_threshold", "0.1");
|
pref("dom.vr.controller_trigger_threshold", "0.1");
|
||||||
// Enable external XR API integrations
|
// 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);
|
pref("dom.vr.external.enabled", false);
|
||||||
|
#endif
|
||||||
// Minimum number of milliseconds the browser will wait before attempting
|
// Minimum number of milliseconds the browser will wait before attempting
|
||||||
// to re-start the VR service after an enumeration returned no devices.
|
// to re-start the VR service after an enumeration returned no devices.
|
||||||
pref("dom.vr.external.notdetected.timeout", 60000);
|
pref("dom.vr.external.notdetected.timeout", 60000);
|
||||||
|
|
@ -5423,8 +5427,8 @@ pref("dom.vr.poseprediction.enabled", true);
|
||||||
// tests or in a headless kiosk system.
|
// tests or in a headless kiosk system.
|
||||||
pref("dom.vr.require-gesture", true);
|
pref("dom.vr.require-gesture", true);
|
||||||
// Enable a separate process for VR module.
|
// Enable a separate process for VR module.
|
||||||
#if defined(XP_WIN)
|
#if defined(XP_WIN) && defined(NIGHTLY_BUILD)
|
||||||
pref("dom.vr.process.enabled", false);
|
pref("dom.vr.process.enabled", true);
|
||||||
#endif
|
#endif
|
||||||
// Puppet device, used for simulating VR hardware within tests and dev tools
|
// Puppet device, used for simulating VR hardware within tests and dev tools
|
||||||
pref("dom.vr.puppet.enabled", false);
|
pref("dom.vr.puppet.enabled", false);
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script>
|
<script>
|
||||||
|
SimpleTest.requestCompleteLog();
|
||||||
|
|
||||||
// All the requests are sent to test_accept_header.sjs which will return
|
// All the requests are sent to test_accept_header.sjs which will return
|
||||||
// different content based on the queryString. When the queryString is 'get',
|
// 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() {
|
function test_iframe() {
|
||||||
let observer = new PerformanceObserver(function(list, obj) {
|
let observer = new PerformanceObserver(function(list, obj) {
|
||||||
obj.disconnect();
|
list.getEntries().forEach(entry => info(entry.name));
|
||||||
|
|
||||||
list.getEntries().forEach(entry => {
|
list.getEntries().forEach(entry => {
|
||||||
if (entry.name.endsWith("test_accept_header.sjs?iframe")) {
|
if (entry.name.endsWith("test_accept_header.sjs?iframe")) {
|
||||||
obj.disconnect();
|
obj.disconnect();
|
||||||
|
|
@ -51,8 +51,7 @@ function test_image() {
|
||||||
|
|
||||||
function test_style() {
|
function test_style() {
|
||||||
let observer = new PerformanceObserver(function(list, obj) {
|
let observer = new PerformanceObserver(function(list, obj) {
|
||||||
obj.disconnect();
|
list.getEntries().forEach(entry => info(entry.name));
|
||||||
|
|
||||||
list.getEntries().forEach(entry => {
|
list.getEntries().forEach(entry => {
|
||||||
if (entry.name.endsWith("test_accept_header.sjs?style")) {
|
if (entry.name.endsWith("test_accept_header.sjs?style")) {
|
||||||
obj.disconnect();
|
obj.disconnect();
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
function handleRequest(request, response) {
|
function handleRequest(request, response) {
|
||||||
response.setStatusLine(request.httpVersion, "200", "OK");
|
response.setStatusLine(request.httpVersion, "200", "OK");
|
||||||
|
dump(`test_accept_header ${request.path}?${request.queryString}\n`);
|
||||||
|
|
||||||
if (request.queryString == "worker") {
|
if (request.queryString == "worker") {
|
||||||
response.setHeader("Content-Type", "application/json", false);
|
response.setHeader("Content-Type", "text/javascript", false);
|
||||||
response.write("postMessage(42)");
|
response.write("postMessage(42)");
|
||||||
|
|
||||||
setState("data", JSON.stringify({type: "worker", accept: request.getHeader("Accept") }));
|
setState("data", JSON.stringify({type: "worker", accept: request.getHeader("Accept") }));
|
||||||
|
|
@ -39,7 +40,7 @@ function handleRequest(request, response) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.queryString == "get") {
|
if (request.queryString == "get") {
|
||||||
response.setHeader("Content-Type", "text/javascript", false);
|
response.setHeader("Content-Type", "application/json", false);
|
||||||
response.write(getState("data"));
|
response.write(getState("data"));
|
||||||
|
|
||||||
setState("data", "");
|
setState("data", "");
|
||||||
|
|
|
||||||
|
|
@ -44,20 +44,40 @@ following are valid:
|
||||||
Auto Completion
|
Auto Completion
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
A `bash completion`_ script is bundled with mach. To enable it with ``bash``,
|
A `bash completion`_ script is bundled with mach, it can be used with either ``bash`` or ``zsh``.
|
||||||
add the following to your ``~/.bashrc``, ``~/.bash_profile`` or equivalent:
|
|
||||||
|
Bash
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
Add the following to your ``~/.bashrc``, ``~/.bash_profile`` or equivalent:
|
||||||
|
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
source <srcdir>/python/mach/bash-completion.sh
|
source <srcdir>/python/mach/bash-completion.sh
|
||||||
|
|
||||||
This script can also be used with ``zsh``. Add this to your ``~/.zshrc`` or
|
.. tip::
|
||||||
equivalent:
|
|
||||||
|
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
|
.. code-block:: shell
|
||||||
|
|
||||||
autoload bashcompinit
|
autoload -U bashcompinit && 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
|
source <srcdir>/python/mach/bash-completion.sh
|
||||||
|
|
||||||
Don't forget to substitute ``<srcdir>`` with the path to your checkout.
|
Don't forget to substitute ``<srcdir>`` with the path to your checkout.
|
||||||
|
|
|
||||||
|
|
@ -72,19 +72,34 @@ class BuiltinCommands(object):
|
||||||
args = args[i+1:]
|
args = args[i+1:]
|
||||||
break
|
break
|
||||||
|
|
||||||
|
# If no command is typed yet, just offer the commands.
|
||||||
if not command:
|
if not command:
|
||||||
print("\n".join(all_commands))
|
print("\n".join(all_commands))
|
||||||
return
|
return
|
||||||
|
|
||||||
handler = self.context.commands.command_handlers[command]
|
handler = self.context.commands.command_handlers[command]
|
||||||
|
# If a subcommand was typed, update the handler.
|
||||||
for arg in args:
|
for arg in args:
|
||||||
if arg in handler.subcommand_handlers:
|
if arg in handler.subcommand_handlers:
|
||||||
handler = handler.subcommand_handlers[arg]
|
handler = handler.subcommand_handlers[arg]
|
||||||
break
|
break
|
||||||
|
|
||||||
parser = handler.parser
|
|
||||||
targets = sorted(handler.subcommand_handlers.keys())
|
targets = sorted(handler.subcommand_handlers.keys())
|
||||||
if not is_help:
|
if is_help:
|
||||||
targets.append('help')
|
print("\n".join(targets))
|
||||||
targets.extend(chain(*[action.option_strings for action in parser._actions]))
|
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))
|
print("\n".join(targets))
|
||||||
|
|
|
||||||
|
|
@ -299,6 +299,30 @@ raptor-tp6-8-chrome:
|
||||||
- --test=raptor-tp6-8
|
- --test=raptor-tp6-8
|
||||||
- --app=chrome
|
- --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:
|
raptor-tp6-10-firefox:
|
||||||
description: "Raptor tp6-10 on Firefox"
|
description: "Raptor tp6-10 on Firefox"
|
||||||
try-name: raptor-tp6-10-firefox
|
try-name: raptor-tp6-10-firefox
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,7 @@ raptor-firefox:
|
||||||
- raptor-tp6-6-firefox
|
- raptor-tp6-6-firefox
|
||||||
- raptor-tp6-7-firefox
|
- raptor-tp6-7-firefox
|
||||||
- raptor-tp6-8-firefox
|
- raptor-tp6-8-firefox
|
||||||
|
- raptor-tp6-9-firefox
|
||||||
- raptor-tp6-10-firefox
|
- raptor-tp6-10-firefox
|
||||||
- raptor-speedometer-firefox
|
- raptor-speedometer-firefox
|
||||||
- raptor-stylebench-firefox
|
- raptor-stylebench-firefox
|
||||||
|
|
@ -121,6 +122,7 @@ raptor-chrome:
|
||||||
- raptor-tp6-6-chrome
|
- raptor-tp6-6-chrome
|
||||||
- raptor-tp6-7-chrome
|
- raptor-tp6-7-chrome
|
||||||
- raptor-tp6-8-chrome
|
- raptor-tp6-8-chrome
|
||||||
|
- raptor-tp6-9-firefox
|
||||||
- raptor-tp6-10-chrome
|
- raptor-tp6-10-chrome
|
||||||
- raptor-speedometer-chrome
|
- raptor-speedometer-chrome
|
||||||
- raptor-stylebench-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
|
# This list is based on kGeckoProcessTypeString. ipdlunittest processes likely
|
||||||
# are not going to produce leak logs we will ever see.
|
# 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:
|
for processType in knownProcessTypes:
|
||||||
log.info("TEST-INFO | leakcheck | %s process: leak threshold set at %d bytes"
|
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-6.ini]
|
||||||
[include:tests/raptor-tp6-7.ini]
|
[include:tests/raptor-tp6-7.ini]
|
||||||
[include:tests/raptor-tp6-8.ini]
|
[include:tests/raptor-tp6-8.ini]
|
||||||
|
[include:tests/raptor-tp6-9.ini]
|
||||||
[include:tests/raptor-tp6-10.ini]
|
[include:tests/raptor-tp6-10.ini]
|
||||||
|
|
||||||
# raptor benchmark tests
|
# 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/*",
|
"*://*.instagram.com/*",
|
||||||
"*://*.microsoft.com/*",
|
"*://*.microsoft.com/*",
|
||||||
"*://*.paypal.com/*",
|
"*://*.paypal.com/*",
|
||||||
|
"*://*.pinterest.com/*",
|
||||||
"*://*.reddit.com/*",
|
"*://*.reddit.com/*",
|
||||||
"*://*.twitter.com/*",
|
"*://*.twitter.com/*",
|
||||||
"*://*.vice.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]
|
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]
|
[MediaRecorder-stop.html]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
[MediaRecorder will stop recording and fire a stop event when stop() is called]
|
[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]
|
[MediaRecorder will stop recording and fire a stop event when all tracks are ended]
|
||||||
expected: TIMEOUT
|
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();
|
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 video = createVideoStream();
|
||||||
let recorder = new MediaRecorder(video);
|
let recorder = new MediaRecorder(video);
|
||||||
recorder.onstop = t.step_func(errorEvent => {
|
let events = recordEvents(recorder,
|
||||||
assert_equals(errorEvent.type, 'stop', 'the error type should be stop');
|
["start", "stop", "dataavailable", "pause", "resume", "error"]);
|
||||||
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();
|
|
||||||
});
|
|
||||||
assert_equals(video.getVideoTracks().length, 1, "video mediastream starts with one track");
|
assert_equals(video.getVideoTracks().length, 1, "video mediastream starts with one track");
|
||||||
recorder.start();
|
recorder.start();
|
||||||
assert_equals(recorder.state, "recording", "MediaRecorder has been started successfully");
|
assert_equals(recorder.state, "recording", "MediaRecorder has been started successfully");
|
||||||
|
|
||||||
video.getVideoTracks()[0].stop();
|
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");
|
}, "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 video = createVideoStream();
|
||||||
let recorder = new MediaRecorder(video);
|
let recorder = new MediaRecorder(video);
|
||||||
recorder.onstop = t.step_func(errorEvent => {
|
let events = recordEvents(recorder,
|
||||||
assert_equals(errorEvent.type, 'stop', 'the error type should be stop');
|
["start", "stop", "dataavailable", "pause", "resume", "error"]);
|
||||||
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();
|
|
||||||
});
|
|
||||||
recorder.start();
|
recorder.start();
|
||||||
assert_equals(recorder.state, "recording", "MediaRecorder has been started successfully");
|
assert_equals(recorder.state, "recording", "MediaRecorder has been started successfully");
|
||||||
|
|
||||||
recorder.stop();
|
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");
|
}, "MediaRecorder will stop recording and fire a stop event when stop() is called");
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,9 @@ with Files('gmp-sources/*'):
|
||||||
with Files('tests/browser/browser_audio*'):
|
with Files('tests/browser/browser_audio*'):
|
||||||
BUG_COMPONENT = ('Core', 'Audio/Video: Playback')
|
BUG_COMPONENT = ('Core', 'Audio/Video: Playback')
|
||||||
|
|
||||||
|
with Files('tests/browser/browser_autoplay*'):
|
||||||
|
BUG_COMPONENT = ('Core', 'Audio/Video: Playback')
|
||||||
|
|
||||||
with Files('tests/browser/*block*'):
|
with Files('tests/browser/*block*'):
|
||||||
BUG_COMPONENT = ('Core', 'Audio/Video: Playback')
|
BUG_COMPONENT = ('Core', 'Audio/Video: Playback')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -377,17 +377,22 @@ class MozBrowser extends MozElementMixin(XULFrameElement) {
|
||||||
|
|
||||||
set docShellIsActive(val) {
|
set docShellIsActive(val) {
|
||||||
if (this.isRemoteBrowser) {
|
if (this.isRemoteBrowser) {
|
||||||
this.frameLoader.tabParent.docShellIsActive = val;
|
let { frameLoader } = this;
|
||||||
return val;
|
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() {
|
get docShellIsActive() {
|
||||||
if (this.isRemoteBrowser) {
|
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;
|
return this.docShell && this.docShell.isActive;
|
||||||
}
|
}
|
||||||
|
|
@ -396,11 +401,11 @@ class MozBrowser extends MozElementMixin(XULFrameElement) {
|
||||||
if (this.isRemoteBrowser) {
|
if (this.isRemoteBrowser) {
|
||||||
let { frameLoader } = this;
|
let { frameLoader } = this;
|
||||||
if (frameLoader && frameLoader.tabParent) {
|
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() {
|
get renderLayers() {
|
||||||
|
|
@ -417,7 +422,7 @@ class MozBrowser extends MozElementMixin(XULFrameElement) {
|
||||||
get hasLayers() {
|
get hasLayers() {
|
||||||
if (this.isRemoteBrowser) {
|
if (this.isRemoteBrowser) {
|
||||||
let { frameLoader } = this;
|
let { frameLoader } = this;
|
||||||
if (frameLoader.tabParent) {
|
if (frameLoader && frameLoader.tabParent) {
|
||||||
return frameLoader.tabParent.hasLayers;
|
return frameLoader.tabParent.hasLayers;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -727,7 +732,6 @@ class MozBrowser extends MozElementMixin(XULFrameElement) {
|
||||||
set userTypedValue(val) {
|
set userTypedValue(val) {
|
||||||
this.urlbarChangeTracker.userTyped();
|
this.urlbarChangeTracker.userTyped();
|
||||||
this._userTypedValue = val;
|
this._userTypedValue = val;
|
||||||
return val;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get userTypedValue() {
|
get userTypedValue() {
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ codespell:
|
||||||
- mobile/locales/en-US/
|
- mobile/locales/en-US/
|
||||||
- netwerk/locales/en-US/
|
- netwerk/locales/en-US/
|
||||||
- python/docs/
|
- python/docs/
|
||||||
|
- python/mach/docs/
|
||||||
- python/mozlint/
|
- python/mozlint/
|
||||||
- python/safety/
|
- python/safety/
|
||||||
- services/sync/locales/en-US/
|
- services/sync/locales/en-US/
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||||
const NSMouseMoved = 5;
|
const NSMouseMoved = 5;
|
||||||
|
|
||||||
var gLeftWindow, gRightWindow, gIFrame;
|
var gLeftWindow, gRightWindow, gBrowserElement;
|
||||||
var gExpectedEvents = [];
|
var gExpectedEvents = [];
|
||||||
|
|
||||||
function moveMouseTo(x, y, andThen) {
|
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');
|
gLeftWindow = open('empty_window.xul', '_blank', 'chrome,screenX=50,screenY=50,width=200,height=200');
|
||||||
SimpleTest.waitForFocus(function () {
|
SimpleTest.waitForFocus(function () {
|
||||||
gRightWindow = open('empty_window.xul', '', 'chrome,screenX=300,screenY=50,width=200,height=200');
|
gRightWindow = open('empty_window.xul', '', 'chrome,screenX=300,screenY=50,width=200,height=200');
|
||||||
SimpleTest.waitForFocus(attachIFrameToRightWindow, gRightWindow);
|
SimpleTest.waitForFocus(attachBrowserToLeftWindow, gRightWindow);
|
||||||
}, gLeftWindow);
|
}, gLeftWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
function attachIFrameToRightWindow() {
|
function attachBrowserToLeftWindow() {
|
||||||
gIFrame = gLeftWindow.document.createElementNS(XUL_NS, "iframe");
|
gBrowserElement = gLeftWindow.document.createXULElement("browser");
|
||||||
gIFrame.setAttribute("type", "content");
|
gBrowserElement.setAttribute("type", "content");
|
||||||
gIFrame.setAttribute("clickthrough", "never");
|
gBrowserElement.setAttribute("src", "file_bug596600.html");
|
||||||
gIFrame.setAttribute("src", "file_bug596600.html");
|
gBrowserElement.style.width = "100px";
|
||||||
gIFrame.style.width = "100px";
|
gBrowserElement.style.height = "100px";
|
||||||
gIFrame.style.height = "100px";
|
gBrowserElement.style.margin = "50px";
|
||||||
gIFrame.style.margin = "50px";
|
gLeftWindow.document.documentElement.appendChild(gBrowserElement);
|
||||||
gLeftWindow.document.documentElement.appendChild(gIFrame);
|
gBrowserElement.addEventListener("load", function (e) {
|
||||||
gIFrame.addEventListener("load", function (e) {
|
|
||||||
gIFrame.removeEventListener("load", arguments.callee, true);
|
|
||||||
test1();
|
test1();
|
||||||
}, true);
|
}, { capture: true, once: true });
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function test1() {
|
function test1() {
|
||||||
|
|
@ -76,7 +73,7 @@ function test1() {
|
||||||
moveMouseTo(80, 80, function () {
|
moveMouseTo(80, 80, function () {
|
||||||
ok(!expectMouseOver, "Should have got mouseover event");
|
ok(!expectMouseOver, "Should have got mouseover event");
|
||||||
|
|
||||||
// Move over the iframe, which has clickthrough="never".
|
// Move over the browser
|
||||||
expectMouseOut = true;
|
expectMouseOut = true;
|
||||||
moveMouseTo(150, 150, function () {
|
moveMouseTo(150, 150, function () {
|
||||||
ok (!expectMouseOut, "Should have got mouseout event");
|
ok (!expectMouseOut, "Should have got mouseout event");
|
||||||
|
|
@ -89,12 +86,12 @@ function test1() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function test2() {
|
function test2() {
|
||||||
// Make the iframe cover the whole window.
|
// Make the browser cover the whole window.
|
||||||
gIFrame.style.margin = "0";
|
gBrowserElement.style.margin = "0";
|
||||||
gIFrame.style.width = gIFrame.style.height = "200px";
|
gBrowserElement.style.width = gBrowserElement.style.height = "200px";
|
||||||
|
|
||||||
// Add a box to the iframe at the left edge.
|
// Add a box to the browser at the left edge.
|
||||||
var doc = gIFrame.contentDocument;
|
var doc = gBrowserElement.contentDocument;
|
||||||
var box = doc.createElement("div");
|
var box = doc.createElement("div");
|
||||||
box.setAttribute("id", "box");
|
box.setAttribute("id", "box");
|
||||||
box.style.position = "absolute";
|
box.style.position = "absolute";
|
||||||
|
|
@ -105,7 +102,7 @@ function test2() {
|
||||||
box.style.backgroundColor = "green";
|
box.style.backgroundColor = "green";
|
||||||
doc.body.appendChild(box);
|
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
|
// A function to waitForFocus and then wait for synthetic mouse
|
||||||
// events to happen. Note that those happen off the refresh driver,
|
// events to happen. Note that those happen off the refresh driver,
|
||||||
|
|
@ -134,22 +131,22 @@ function test2() {
|
||||||
|
|
||||||
// Move the mouse over the box.
|
// Move the mouse over the box.
|
||||||
moveMouseTo(100, 150, function () {
|
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.
|
// Activate the left window.
|
||||||
changeFocusAndAwaitSyntheticMouse(function () {
|
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");
|
ok(box.matches(":hover"), "Box should be hovered");
|
||||||
// De-activate the window (by activating the right window).
|
// De-activate the window (by activating the right window).
|
||||||
changeFocusAndAwaitSyntheticMouse(function () {
|
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");
|
ok(!box.matches(":hover"), "Box shouldn't be hovered");
|
||||||
// Re-activate it.
|
// Re-activate it.
|
||||||
changeFocusAndAwaitSyntheticMouse(function () {
|
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");
|
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 () {
|
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");
|
ok(!box.matches(":hover"), "box shouldn't be hovered");
|
||||||
finalize();
|
finalize();
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue