Merge m-c to autoland, a=merge

MozReview-Commit-ID: AHxJvcR2Tpa
This commit is contained in:
Wes Kocher 2017-09-20 17:47:16 -07:00
commit 1ea82f66aa
199 changed files with 2176 additions and 1717 deletions

View File

@ -1502,7 +1502,7 @@ DocAccessible::DoInitialUpdate()
}
#if defined(XP_WIN)
IAccessibleHolder holder(CreateHolderFromAccessible(this));
IAccessibleHolder holder(CreateHolderFromAccessible(WrapNotNull(this)));
MOZ_DIAGNOSTIC_ASSERT(!holder.IsNull());
int32_t childID = AccessibleWrap::GetChildIDFor(this);
#else

View File

@ -11,6 +11,7 @@
#include "mozilla/a11y/Accessible.h"
#include "mozilla/a11y/Platform.h"
#include "mozilla/a11y/HandlerProvider.h"
#include "mozilla/Assertions.h"
#include "mozilla/Move.h"
#include "mozilla/mscom/MainThreadHandoff.h"
#include "mozilla/mscom/Utils.h"
@ -26,16 +27,13 @@ namespace mozilla {
namespace a11y {
IAccessibleHolder
CreateHolderFromAccessible(Accessible* aAccToWrap)
CreateHolderFromAccessible(NotNull<Accessible*> aAccToWrap)
{
MOZ_ASSERT(aAccToWrap && NS_IsMainThread());
if (!aAccToWrap) {
return nullptr;
}
MOZ_ASSERT(NS_IsMainThread());
STAUniquePtr<IAccessible> iaToProxy;
aAccToWrap->GetNativeInterface(mscom::getter_AddRefs(iaToProxy));
MOZ_ASSERT(iaToProxy);
MOZ_DIAGNOSTIC_ASSERT(iaToProxy);
if (!iaToProxy) {
return nullptr;
}
@ -53,7 +51,7 @@ CreateHolderFromAccessible(Accessible* aAccToWrap)
ProxyUniquePtr<IAccessible> intercepted;
HRESULT hr = MainThreadHandoff::WrapInterface(Move(iaToProxy), payload,
(IAccessible**) mscom::getter_AddRefs(intercepted));
MOZ_ASSERT(SUCCEEDED(hr));
MOZ_DIAGNOSTIC_ASSERT(SUCCEEDED(hr));
if (FAILED(hr)) {
return nullptr;
}

View File

@ -9,6 +9,7 @@
#include "mozilla/a11y/AccessibleHandler.h"
#include "mozilla/mscom/COMPtrHolder.h"
#include "mozilla/NotNull.h"
#include <oleacc.h>
@ -21,7 +22,7 @@ typedef mozilla::mscom::COMPtrHolder<IDispatch, IID_IDispatch> IDispatchHolder;
class Accessible;
IAccessibleHolder
CreateHolderFromAccessible(Accessible* aAccToWrap);
CreateHolderFromAccessible(NotNull<Accessible*> aAccToWrap);
typedef mozilla::mscom::COMPtrHolder<IHandlerControl, IID_IHandlerControl> IHandlerControlHolder;

View File

@ -23,9 +23,6 @@ const EXPECTED_REFLOWS_FIRST_OPEN = [
"handleOverUnderflow@chrome://global/content/bindings/autocomplete.xml",
"_onChanged@chrome://global/content/bindings/autocomplete.xml",
"_appendCurrentResult/<@chrome://global/content/bindings/autocomplete.xml",
"setTimeout handler*_appendCurrentResult@chrome://global/content/bindings/autocomplete.xml",
"_invalidate@chrome://global/content/bindings/autocomplete.xml",
"invalidate@chrome://global/content/bindings/autocomplete.xml"
],
times: 18, // This number should only ever go down - never up.
},
@ -67,8 +64,6 @@ const EXPECTED_REFLOWS_FIRST_OPEN = [
stack: [
"adjustHeight@chrome://global/content/bindings/autocomplete.xml",
"_invalidate/this._adjustHeightTimeout<@chrome://global/content/bindings/autocomplete.xml",
"setTimeout handler*_invalidate@chrome://global/content/bindings/autocomplete.xml",
"invalidate@chrome://global/content/bindings/autocomplete.xml",
],
times: 51, // This number should only ever go down - never up.
},

View File

@ -1,8 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="142" height="38" viewBox="0 0 142 38">
<svg xmlns="http://www.w3.org/2000/svg" width="338" height="42" viewBox="0 0 338 42">
<path d="M136.837 10.212H131.5l-5.7 9.9-5.645-9.9h-5.542l8.364 12.778-9.437 14.265h5.337l6.723-11.443 6.62 11.444h5.7l-9.391-14.471zM22.844 37.255h4.721V10.212h-4.721zm15.42-21.339l-.462-5.7h-4.054v27.039h4.721V23.306c0-4.205 3.079-8.878 6.466-8.878a8.485 8.485 0 0 1 2.36.308l.872-4.618A11.5 11.5 0 0 0 45.5 9.81c-3.284 0-5.8 2.053-7.236 6.106zM0 37.255h4.875V21.707h11.546v-3.849H4.875V5.8h13.342l.564-3.9H0zM25.153.163A3.14 3.14 0 0 0 21.869 3.4a3.128 3.128 0 0 0 3.284 3.182A3.143 3.143 0 0 0 28.489 3.4 3.154 3.154 0 0 0 25.153.163zm76.491 9.647c-7.7 0-12.111 5.585-12.111 13.949 0 8.57 4.362 14.112 12.059 14.112 7.646 0 12.059-5.8 12.059-14.163.001-8.57-4.309-13.898-12.007-13.898zm-.051 24.264c-4.516 0-6.979-3.284-6.979-10.315 0-7.082 2.515-10.152 7.03-10.152 4.464 0 6.928 3.07 6.928 10.1 0 7.083-2.463 10.367-6.979 10.367zM82.47 8.339c0-2.617 1.026-4.541 4-4.541a11.567 11.567 0 0 1 4.721 1.026l1.488-3.438A14.913 14.913 0 0 0 86.216 0c-5.491 0-8.467 3.447-8.467 7.963v2.249h-4.824v3.643h4.824v23.4h4.721v-23.4h6.055l.513-3.643H82.47zM59.952 9.81c-6.979 0-11.238 5.79-11.238 14.206 0 8.57 4.413 13.855 11.957 13.855a14.741 14.741 0 0 0 9.442-3.387l-2.053-2.822a11.384 11.384 0 0 1-7.03 2.361c-3.9 0-6.825-2.412-7.287-8.672h17.242c.051-.616.1-1.488.1-2.412.003-8.263-3.846-13.129-11.133-13.129zm6.466 12.051H53.743c.359-6 2.72-8.3 6.312-8.3 4.259 0 6.363 2.711 6.363 8z" fill="#fff"/>
<path d="M139.854 10.228a2.134 2.134 0 0 0-2.128 2.155 2.093 2.093 0 0 0 2.128 2.12 2.137 2.137 0 1 0 0-4.275zm0 3.954a1.755 1.755 0 0 1-1.772-1.8 1.783 1.783 0 0 1 1.772-1.826 1.761 1.761 0 0 1 1.79 1.808 1.779 1.779 0 0 1-1.79 1.819zm.891-2.333c0-.481-.33-.721-1.015-.721h-.614v2.422h.374v-.988h.321l.579.988h.445l-.659-1.051a.659.659 0 0 0 .568-.65zm-1.256.4v-.81h.294c.374 0 .579.1.579.41 0 .294-.2.4-.525.4z" fill="#fff"/>
<path d="M182.953 39.384L180.9 42c-3.8-3.386-7.284-4.309-13.542-4.309-8.464 0-14.312-6.258-14.312-17.954 0-11.593 5.9-18.21 14.312-18.21 8.566 0 14.363 6.309 14.363 18.159 0 9.644-3.693 14.414-8.874 16.312a16.2 16.2 0 0 1 10.106 3.386zm-15.594-4.206c6.874 0 11.131-4.924 11.131-15.491 0-10.67-4.36-15.543-11.131-15.543-6.617 0-11.08 4.924-11.08 15.594 0 10.515 4.566 15.44 11.08 15.44z" fill="#fff"/>
<path d="M206.037 37.229h-2.565l-.154-4.771c-1.9 3.18-4.617 5.335-8.772 5.335-4.822 0-7.592-2.924-7.592-8.207V10.4h2.975v18.879c0 4.258 1.8 6.053 5.283 6.053 3.539 0 6-2.308 7.848-5.489V10.4h2.975z" fill="#fff"/>
<path d="M232.505 35.691l-.667 2.1a4.731 4.731 0 0 1-4.155-4.463 9.45 9.45 0 0 1-8.361 4.463c-5.181 0-8.31-3.232-8.31-8 0-5.643 4.258-8.669 11.131-8.669h5.13v-2.615c0-4.258-1.744-6.155-6.207-6.155a21.849 21.849 0 0 0-7.284 1.539l-.769-2.257a22.421 22.421 0 0 1 8.464-1.8c6.1 0 8.772 3.026 8.772 8.515v12.93c-.001 2.975.82 3.847 2.256 4.412zm-5.232-5.13v-7.284h-4.668c-5.386 0-8.413 2.1-8.413 6.361 0 3.693 2.1 5.745 5.643 5.745 3.437 0 5.797-1.693 7.438-4.822z" fill="#fff"/>
<path d="M256.82 18.045v19.184h-2.975V18.455c0-4.411-1.8-6.207-5.078-6.207-3.642 0-6.1 2.257-8.31 5.54v19.441h-2.975V10.4h2.565l.256 4.565c2.154-3.026 5.13-5.13 9.028-5.13 4.869.003 7.489 3.029 7.489 8.21z" fill="#fff"/>
<path d="M276.312 36.1a10.026 10.026 0 0 1-5.643 1.693c-4.052 0-6.566-2.411-6.566-7.079v-17.9h-4.513V10.4h4.51V3.99l2.975-.359V10.4H274l-.359 2.411h-6.566v17.75c0 3.129 1.231 4.668 3.95 4.668a7.523 7.523 0 0 0 4.1-1.231z" fill="#fff"/>
<path d="M297.856 37.229h-2.565l-.154-4.771c-1.9 3.18-4.617 5.335-8.772 5.335-4.822 0-7.592-2.924-7.592-8.207V10.4h2.975v18.879c0 4.258 1.8 6.053 5.284 6.053 3.539 0 6-2.308 7.848-5.489V10.4h2.975z" fill="#fff"/>
<path d="M337.251 18.045v19.184h-2.975V18.455c0-4.36-1.8-6.207-4.565-6.207-3.232 0-5.489 2.257-7.54 5.54v19.441H319.2V18.455c0-4.36-1.8-6.207-4.565-6.207-3.232 0-5.54 2.257-7.541 5.54v19.441h-2.975V10.4h2.565l.256 4.514c2-3.026 4.771-5.078 8.259-5.078a6.432 6.432 0 0 1 6.617 5.335c2.1-3.18 4.873-5.335 8.464-5.335 4.304.002 6.971 3.131 6.971 8.209z" fill="#fff"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -865,6 +865,11 @@ var MessageQueue = {
* An IdleDeadline object passed by requestIdleCallback().
*/
sendWhenIdle(deadline) {
if (!content) {
// The frameloader is being torn down. Nothing more to do.
return;
}
if (deadline) {
if (deadline.didTimeout || deadline.timeRemaining() > MessageQueue.NEEDED_IDLE_PERIOD_MS) {
MessageQueue.send();

View File

@ -37,7 +37,7 @@ function clickOnElement(selector) {
SimpleTest.executeSoon(() => element.click());
}
async function onStorageChanged(type) {
async function onAddressChanged(type) {
return new Promise(resolve => {
formFillChromeScript.addMessageListener("formautofill-storage-changed", function onChanged(data) {
formFillChromeScript.removeMessageListener("formautofill-storage-changed", onChanged);
@ -58,58 +58,60 @@ function checkMenuEntries(expectedValues, isFormAutofillResult = true) {
}
}
function invokeAsyncChromeTask(message, response, payload = {}) {
async function addAddress(address) {
return new Promise(resolve => {
formFillChromeScript.sendAsyncMessage(message, payload);
formFillChromeScript.addMessageListener(response, function onReceived(data) {
formFillChromeScript.removeMessageListener(response, onReceived);
formFillChromeScript.sendAsyncMessage("FormAutofillTest:AddAddress", {address});
formFillChromeScript.addMessageListener("FormAutofillTest:AddressAdded", function onAdded(data) {
formFillChromeScript.removeMessageListener("FormAutofillTest:AddressAdded", onAdded);
SimpleTest.requestFlakyTimeout("Ensure ProfileAutocomplete is registered");
setTimeout(resolve, 500);
});
});
}
async function removeAddress(guid) {
return new Promise(resolve => {
formFillChromeScript.sendAsyncMessage("FormAutofillTest:RemoveAddress", {guid});
formFillChromeScript.addMessageListener("FormAutofillTest:AddressRemoved", function onDeleted(data) {
formFillChromeScript.removeMessageListener("FormAutofillTest:AddressRemoved", onDeleted);
resolve();
});
});
}
async function updateAddress(guid, address) {
return new Promise(resolve => {
formFillChromeScript.sendAsyncMessage("FormAutofillTest:UpdateAddress", {address, guid});
formFillChromeScript.addMessageListener("FormAutofillTest:AddressUpdated", function onUpdated(data) {
formFillChromeScript.removeMessageListener("FormAutofillTest:AddressUpdated", onUpdated);
resolve();
});
});
}
async function checkAddresses(expectedAddresses) {
return new Promise(resolve => {
formFillChromeScript.sendAsyncMessage("FormAutofillTest:CheckAddresses", {expectedAddresses});
formFillChromeScript.addMessageListener("FormAutofillTest:areAddressesMatching", function onChecked(data) {
formFillChromeScript.removeMessageListener("FormAutofillTest:areAddressesMatching", onChecked);
resolve(data);
});
});
}
async function addAddress(address) {
await invokeAsyncChromeTask("FormAutofillTest:AddAddress", "FormAutofillTest:AddressAdded", {address});
await sleep();
}
async function cleanUpAddress() {
return new Promise(resolve => {
formFillChromeScript.sendAsyncMessage("FormAutofillTest:CleanUpAddress", {});
formFillChromeScript.addMessageListener("FormAutofillTest:AddressCleanedUp", function onCleanedUp(data) {
formFillChromeScript.removeMessageListener("FormAutofillTest:AddressCleanedUp", onCleanedUp);
async function removeAddress(guid) {
return invokeAsyncChromeTask("FormAutofillTest:RemoveAddress", "FormAutofillTest:AddressRemoved", {guid});
}
async function updateAddress(guid, address) {
return invokeAsyncChromeTask("FormAutofillTest:UpdateAddress", "FormAutofillTest:AddressUpdated", {address, guid});
}
async function checkAddresses(expectedAddresses) {
return invokeAsyncChromeTask("FormAutofillTest:CheckAddresses", "FormAutofillTest:areAddressesMatching", {expectedAddresses});
}
async function cleanUpAddresses() {
return invokeAsyncChromeTask("FormAutofillTest:CleanUpAddresses", "FormAutofillTest:AddressesCleanedUp");
}
async function addCreditCard(creditcard) {
await invokeAsyncChromeTask("FormAutofillTest:AddCreditCard", "FormAutofillTest:CreditCardAdded", {creditcard});
await sleep();
}
async function removeCreditCard(guid) {
return invokeAsyncChromeTask("FormAutofillTest:RemoveCreditCard", "FormAutofillTest:CreditCardRemoved", {guid});
}
async function checkCreditCards(expectedCreditCards) {
return invokeAsyncChromeTask("FormAutofillTest:CheckCreditCards", "FormAutofillTest:areCreditCardsMatching", {expectedCreditCards});
}
async function cleanUpCreditCards() {
return invokeAsyncChromeTask("FormAutofillTest:CleanUpCreditCards", "FormAutofillTest:CreditCardsCleanedUp");
}
async function cleanUpStorage() {
await cleanUpAddresses();
await cleanUpCreditCards();
resolve(data);
});
});
}
// Utils for registerPopupShownListener(in satchel_common.js) that handles dropdown popup

View File

@ -7,192 +7,113 @@
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://formautofill/FormAutofillUtils.jsm");
let {profileStorage} = Cu.import("resource://formautofill/ProfileStorage.jsm", {});
const {ADDRESSES_COLLECTION_NAME, CREDITCARDS_COLLECTION_NAME} = FormAutofillUtils;
var ParentUtils = {
async _getRecords(collectionName) {
return new Promise(resolve => {
Services.cpmm.addMessageListener("FormAutofill:Records", function getResult({data}) {
Services.cpmm.removeMessageListener("FormAutofill:Records", getResult);
resolve(data);
});
Services.cpmm.sendAsyncMessage("FormAutofill:GetRecords", {searchString: "", collectionName});
cleanUpAddress() {
Services.cpmm.addMessageListener("FormAutofill:Records", function getResult(result) {
Services.cpmm.removeMessageListener("FormAutofill:Records", getResult);
let addresses = result.data;
Services.cpmm.sendAsyncMessage("FormAutofill:RemoveAddresses",
{guids: addresses.map(address => address.guid)});
let count = addresses.length;
Services.obs.addObserver(function observer(subject, topic, data) {
if (!--count) {
Services.obs.removeObserver(observer, topic);
sendAsyncMessage("FormAutofillTest:AddressCleanedUp");
}
}, "formautofill-storage-changed");
});
Services.cpmm.sendAsyncMessage("FormAutofill:GetRecords", {searchString: "", collectionName: "addresses"});
},
async _storageChangeObserved({topic = "formautofill-storage-changed", type, times = 1}) {
let count = times;
return new Promise(resolve => {
Services.obs.addObserver(function observer(subject, obsTopic, data) {
if (type && data != type || !!--count) {
return;
}
Services.obs.removeObserver(observer, obsTopic);
resolve();
}, topic);
});
},
async _operateRecord(collectionName, type, msgData, contentMsg) {
let times, topic;
if (collectionName == ADDRESSES_COLLECTION_NAME) {
switch (type) {
case "add": {
Services.cpmm.sendAsyncMessage("FormAutofill:SaveAddress", msgData);
break;
}
case "update": {
Services.cpmm.sendAsyncMessage("FormAutofill:SaveAddress", msgData);
break;
}
case "remove": {
times = msgData.guids.length;
Services.cpmm.sendAsyncMessage("FormAutofill:RemoveAddresses", msgData);
break;
}
updateAddress(type, chromeMsg, msgData, contentMsg) {
Services.cpmm.sendAsyncMessage(chromeMsg, msgData);
Services.obs.addObserver(function observer(subject, topic, data) {
if (data != type) {
return;
}
} else {
switch (type) {
case "add": {
const msgDataCloned = Object.assign({}, msgData);
Services.cpmm.sendAsyncMessage("FormAutofill:SaveCreditCard", msgDataCloned);
break;
}
case "remove": {
times = msgData.guids.length;
Services.cpmm.sendAsyncMessage("FormAutofill:RemoveCreditCards", msgData);
break;
}
}
}
await this._storageChangeObserved({type, times, topic});
sendAsyncMessage(contentMsg);
},
async operateAddress(type, msgData, contentMsg) {
await this._operateRecord(ADDRESSES_COLLECTION_NAME, ...arguments);
},
async operateCreditCard(type, msgData, contentMsg) {
await this._operateRecord(CREDITCARDS_COLLECTION_NAME, ...arguments);
},
async cleanUpAddresses() {
const guids = (await this._getRecords(ADDRESSES_COLLECTION_NAME)).map(record => record.guid);
await this.operateAddress("remove", {guids}, "FormAutofillTest:AddressesCleanedUp");
},
async cleanUpCreditCards() {
const guids = (await this._getRecords(CREDITCARDS_COLLECTION_NAME)).map(record => record.guid);
await this.operateCreditCard("remove", {guids}, "FormAutofillTest:CreditCardsCleanedUp");
},
async cleanup() {
Services.obs.removeObserver(this, "formautofill-storage-changed");
await this.cleanUpAddresses();
await this.cleanUpCreditCards();
},
_areRecordsMatching(recordA, recordB, collectionName) {
for (let field of profileStorage[collectionName].VALID_FIELDS) {
if (recordA[field] !== recordB[field]) {
return false;
}
}
// Check the internal field if both addresses have valid value.
for (let field of profileStorage.INTERNAL_FIELDS) {
if (field in recordA && field in recordB && (recordA[field] !== recordB[field])) {
return false;
}
}
return true;
},
async _checkRecords(collectionName, expectedRecords) {
const records = await this._getRecords(collectionName);
if (records.length !== expectedRecords.length) {
return false;
}
for (let record of records) {
let matching = expectedRecords.some(expectedRecord => {
return ParentUtils._areRecordsMatching(record, expectedRecord, collectionName);
});
if (!matching) {
return false;
}
}
return true;
},
async checkAddresses({expectedAddresses}) {
const areMatched = await this._checkRecords(ADDRESSES_COLLECTION_NAME, expectedAddresses);
sendAsyncMessage("FormAutofillTest:areAddressesMatching", areMatched);
},
async checkCreditCards({expectedCreditCards}) {
const areMatched = await this._checkRecords(CREDITCARDS_COLLECTION_NAME, expectedCreditCards);
sendAsyncMessage("FormAutofillTest:areCreditCardsMatching", areMatched);
Services.obs.removeObserver(observer, topic);
sendAsyncMessage(contentMsg);
}, "formautofill-storage-changed");
},
observe(subject, topic, data) {
assert.ok(topic === "formautofill-storage-changed");
sendAsyncMessage("formautofill-storage-changed", {subject: null, topic, data});
},
cleanup() {
Services.obs.removeObserver(this, "formautofill-storage-changed");
this.cleanUpAddress();
},
areAddressesMatching(addressA, addressB) {
for (let field of profileStorage.addresses.VALID_FIELDS) {
if (addressA[field] !== addressB[field]) {
return false;
}
}
// Check the internal field if both addresses have valid value.
for (let field of profileStorage.INTERNAL_FIELDS) {
if (field in addressA && field in addressB && (addressA[field] !== addressB[field])) {
return false;
}
}
return true;
},
checkAddresses({expectedAddresses}) {
Services.cpmm.addMessageListener("FormAutofill:Records", function getResult(result) {
Services.cpmm.removeMessageListener("FormAutofill:Records", getResult);
let addresses = result.data;
if (addresses.length !== expectedAddresses.length) {
sendAsyncMessage("FormAutofillTest:areAddressesMatching", false);
return;
}
for (let address of addresses) {
let matching = expectedAddresses.some((expectedAddress) => {
return ParentUtils.areAddressesMatching(address, expectedAddress);
});
if (!matching) {
sendAsyncMessage("FormAutofillTest:areAddressesMatching", false);
return;
}
}
sendAsyncMessage("FormAutofillTest:areAddressesMatching", true);
});
Services.cpmm.sendAsyncMessage("FormAutofill:GetRecords", {searchString: "", collectionName: "addresses"});
},
};
Services.obs.addObserver(ParentUtils, "formautofill-storage-changed");
addMessageListener("FormAutofillTest:AddAddress", (msg) => {
ParentUtils.operateAddress("add", msg, "FormAutofillTest:AddressAdded");
ParentUtils.updateAddress("add", "FormAutofill:SaveAddress", msg, "FormAutofillTest:AddressAdded");
});
addMessageListener("FormAutofillTest:RemoveAddress", (msg) => {
ParentUtils.operateAddress("remove", msg, "FormAutofillTest:AddressRemoved");
ParentUtils.updateAddress("remove", "FormAutofill:RemoveAddress", msg, "FormAutofillTest:AddressRemoved");
});
addMessageListener("FormAutofillTest:UpdateAddress", (msg) => {
ParentUtils.operateAddress("update", msg, "FormAutofillTest:AddressUpdated");
ParentUtils.updateAddress("update", "FormAutofill:SaveAddress", msg, "FormAutofillTest:AddressUpdated");
});
addMessageListener("FormAutofillTest:CheckAddresses", (msg) => {
ParentUtils.checkAddresses(msg);
});
addMessageListener("FormAutofillTest:CleanUpAddresses", (msg) => {
ParentUtils.cleanUpAddresses();
});
addMessageListener("FormAutofillTest:AddCreditCard", (msg) => {
ParentUtils.operateCreditCard("add", msg, "FormAutofillTest:CreditCardAdded");
});
addMessageListener("FormAutofillTest:RemoveCreditCard", (msg) => {
ParentUtils.operateCreditCard("remove", msg, "FormAutofillTest:CreditCardRemoved");
});
addMessageListener("FormAutofillTest:CheckCreditCards", (msg) => {
ParentUtils.checkCreditCards(msg);
});
addMessageListener("FormAutofillTest:CleanUpCreditCards", (msg) => {
ParentUtils.cleanUpCreditCards();
addMessageListener("FormAutofillTest:CleanUpAddress", (msg) => {
ParentUtils.cleanUpAddress();
});
addMessageListener("cleanup", () => {

View File

@ -7,9 +7,6 @@ support-files =
[test_autofocus_form.html]
[test_basic_autocomplete_form.html]
[test_basic_creditcard_autocomplete_form.html]
scheme=https
skip-if = debug # Bug 1401454
[test_formautofill_preview_highlight.html]
[test_multiple_forms.html]
[test_on_address_submission.html]

View File

@ -117,7 +117,7 @@ add_task(async function all_saved_fields_less_than_threshold() {
await expectPopup();
checkMenuEntries(["foo@mozilla.com"], false);
await cleanUpAddresses();
await cleanUpAddress();
});
// Form with both history and address storage.

View File

@ -1,248 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test basic autofill</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
<script type="text/javascript" src="formautofill_common.js"></script>
<script type="text/javascript" src="satchel_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
Form autofill test: simple form credit card autofill
<script>
/* import-globals-from ../../../../../testing/mochitest/tests/SimpleTest/SpawnTask.js */
/* import-globals-from ../../../../../toolkit/components/satchel/test/satchel_common.js */
/* import-globals-from formautofill_common.js */
"use strict";
const {FormAutofillUtils} = SpecialPowers.Cu.import("resource://formautofill/FormAutofillUtils.jsm");
const MOCK_STORAGE = [{
"cc-name": "John Doe",
"cc-number": "1234567812345678",
"cc-exp-month": 4,
"cc-exp-year": 2017,
}, {
"cc-name": "Timothy Berners-Lee",
"cc-number": "1111222233334444",
"cc-exp-month": 12,
"cc-exp-year": 2022,
}];
const reducedMockRecord = {
"cc-name": "John Doe",
"cc-number": "1234123456785678",
};
function patchRecordCCNumber(record) {
const ccNumber = record["cc-number"];
const normalizedCCNumber = "*".repeat(ccNumber.length - 4) + ccNumber.substr(-4);
const ccNumberFmt = FormAutofillUtils.fmtMaskedCreditCardLabel(normalizedCCNumber);
return Object.assign({}, record, {ccNumberFmt});
}
function checkElementFilled(element, expectedvalue) {
const focusedElem = document.activeElement;
const promises = [];
promises.push(new Promise(resolve => {
element.addEventListener("input", function onInput() {
ok(true, "Checking " + element.name + " field fires input event");
resolve();
}, {once: true});
}));
// Don't expect that focused input will receive "change" event since focus never move away.
if (element !== focusedElem) {
promises.push(new Promise(resolve => {
element.addEventListener("change", function onChange() {
ok(true, "Checking " + element.name + " field fires change event");
is(element.value, expectedvalue, "Checking " + element.name + " field");
resolve();
}, {once: true});
}));
}
return promises;
}
function checkFormFilled(creditCard) {
let promises = [];
for (let prop in creditCard) {
let element = document.getElementById(prop);
let converted = String(creditCard[prop]); // Convert potential number to string
promises.push(...checkElementFilled(element, converted));
}
doKey("return");
return Promise.all(promises);
}
async function setupCreditCardStorage() {
await addCreditCard(MOCK_STORAGE[0]);
await addCreditCard(MOCK_STORAGE[1]);
}
async function setupFormHistory() {
await updateFormHistory([
{op: "add", fieldname: "cc-name", value: "John Smith"},
{op: "add", fieldname: "cc-exp-year", value: 2023},
]);
}
initPopupListener();
// Form with history only.
add_task(async function history_only_menu_checking() {
await setupFormHistory();
await setInput("#cc-exp-year", "");
doKey("down");
await expectPopup();
checkMenuEntries(["2023"], false);
});
// Display credit card result even if the number of fillable fields is less than the threshold.
add_task(async function all_saved_fields_less_than_threshold() {
await addCreditCard(reducedMockRecord);
await setInput("#cc-name", "");
doKey("down");
await expectPopup();
checkMenuEntries([reducedMockRecord].map(patchRecordCCNumber).map(cc => JSON.stringify({
primary: cc["cc-name"],
secondary: cc.ccNumberFmt.affix + cc.ccNumberFmt.label,
})));
await cleanUpCreditCards();
});
// Form with both history and credit card storage.
add_task(async function check_menu_when_both_existed() {
await setupCreditCardStorage();
await setInput("#cc-number", "");
doKey("down");
await expectPopup();
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(cc => JSON.stringify({
primaryAffix: cc.ccNumberFmt.affix,
primary: cc.ccNumberFmt.label,
secondary: cc["cc-name"],
})));
await setInput("#cc-name", "");
doKey("down");
await expectPopup();
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(cc => JSON.stringify({
primary: cc["cc-name"],
secondary: cc.ccNumberFmt.affix + cc.ccNumberFmt.label,
})));
await setInput("#cc-exp-year", "");
doKey("down");
await expectPopup();
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(cc => JSON.stringify({
primary: cc["cc-exp-year"],
secondary: cc.ccNumberFmt.affix + cc.ccNumberFmt.label,
})));
await setInput("#cc-exp-month", "");
doKey("down");
await expectPopup();
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(cc => JSON.stringify({
primary: cc["cc-exp-month"],
secondary: cc.ccNumberFmt.affix + cc.ccNumberFmt.label,
})));
await cleanUpCreditCards();
});
// Display history search result if no matched data in credit card.
add_task(async function check_fallback_for_mismatched_field() {
await addCreditCard(reducedMockRecord);
await setInput("#cc-exp-year", "");
doKey("down");
await expectPopup();
checkMenuEntries(["2023"], false);
await cleanUpCreditCards();
});
// Display history search result if credit card autofill is disabled.
add_task(async function check_search_result_for_pref_off() {
await setupCreditCardStorage();
await SpecialPowers.pushPrefEnv({
set: [["extensions.formautofill.creditCards.enabled", false]],
});
await setInput("#cc-name", "");
doKey("down");
await expectPopup();
checkMenuEntries(["John Smith"], false);
await SpecialPowers.popPrefEnv();
});
// Autofill the credit card from dropdown menu.
add_task(async function check_fields_after_form_autofill() {
await setInput("#cc-exp-year", 202);
doKey("down");
await expectPopup();
checkMenuEntries(MOCK_STORAGE.slice(1).map(patchRecordCCNumber).map(cc => JSON.stringify({
primary: cc["cc-exp-year"],
secondary: cc.ccNumberFmt.affix + cc.ccNumberFmt.label,
})));
doKey("down");
await checkFormFilled(MOCK_STORAGE[1]);
});
// Fallback to history search after autofill address.
add_task(async function check_fallback_after_form_autofill() {
await setInput("#cc-name", "");
doKey("down");
await expectPopup();
checkMenuEntries(["John Smith"], false);
});
// Resume form autofill once all the autofilled fileds are changed.
add_task(async function check_form_autofill_resume() {
document.querySelector("#cc-name").blur();
document.querySelector("#form1").reset();
await setInput("#cc-name", "");
doKey("down");
await expectPopup();
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(cc => JSON.stringify({
primary: cc["cc-name"],
secondary: cc.ccNumberFmt.affix + cc.ccNumberFmt.label,
})));
});
</script>
<p id="display"></p>
<div id="content">
<form id="form1">
<p>This is a basic form.</p>
<p><label>Name: <input id="cc-name" autocomplete="cc-name"></label></p>
<p><label>Card Number: <input id="cc-number" autocomplete="cc-number"></label></p>
<p><label>Expiration month: <input id="cc-exp-month" autocomplete="cc-exp-month"></label></p>
<p><label>Expiration year: <input id="cc-exp-year" autocomplete="cc-exp-year"></label></p>
<p><label>CSC: <input id="cc-csc" autocomplete="cc-csc"></label></p>
</form>
</div>
<pre id="test"></pre>
</body>
</html>

View File

@ -45,7 +45,7 @@ add_task(async function check_storage_after_form_submitted() {
clickOnElement("input[type=submit]");
let expectedAddresses = TEST_ADDRESSES.slice(0, 1);
await onStorageChanged("add");
await onAddressChanged("add");
// Check if timesUsed is set correctly
expectedAddresses[0].timesUsed = 1;
let matching = await checkAddresses(expectedAddresses);
@ -67,7 +67,7 @@ add_task(async function check_storage_after_another_address_submitted() {
addressesInMenu.push(TEST_ADDRESSES[0]);
// let expectedAddresses = TEST_ADDRESSES.slice(0);
await onStorageChanged("add");
await onAddressChanged("add");
let matching = await checkAddresses(TEST_ADDRESSES);
ok(matching, "New address saved as expected");
@ -93,7 +93,7 @@ add_task(async function new_address_submitted_and_merged() {
let expectedAddresses = TEST_ADDRESSES.slice(0);
// Check if timesUsed is set correctly
expectedAddresses[0].timesUsed = 2;
await onStorageChanged("merge");
await onAddressChanged("merge");
let matching = await checkAddresses(expectedAddresses);
ok(matching, "Address merged as expected");
delete expectedAddresses[0].timesUsed;
@ -114,7 +114,7 @@ add_task(async function check_storage_after_form_submitted() {
clickOnElement("input[type=submit]");
let expectedAddresses = TEST_ADDRESSES.slice(0);
await onStorageChanged("merge");
await onAddressChanged("merge");
let matching = await checkAddresses(expectedAddresses);
ok(matching, "Updated address merged as expected");
});

View File

@ -220,7 +220,7 @@
transition: none;
}
#navigator-toolbox:not(:hover) > #nav-bar:not([customizing="true"]) > #nav-bar-customization-target > #urlbar-container > #urlbar:not([focused]) > .urlbar-textbox-container > .urlbar-history-dropmarker {
#nav-bar:not([customizing="true"]) > #nav-bar-customization-target > #urlbar-container:not(:hover) > #urlbar:not([focused]) > .urlbar-textbox-container > .urlbar-history-dropmarker {
opacity: 0;
}

View File

@ -230,6 +230,37 @@
fun:_ZN7mozilla3dom*Content*
}
# False positives triggered by rust 1.20.0 (at least) builds of stylo.
# See bug 1394696. The diagnosis is an llvm optimization transforming
# `if A && B` to `if B && A` if is can be proven that A is false
# whenever B is uninitialized. Confusing, but valid.
#
# Conditional jump or move depends on uninitialised value(s)
# at 0x113ED01E: selectors::matching::matches_complex_selector_internal (option.rs:421)
# by 0x113ECF19: selectors::matching::matches_complex_selector (matching.rs:501)
# by 0x113EBAC0: <style::selector_map::SelectorMap<style::stylist::Rule>>::get_matching_rules (matching.rs:397)
{
Bug 1394696 Stylo selector, Sept 2017, part 1
Memcheck:Cond
fun:_ZN9selectors8matching33matches_complex_selector_internal*
fun:_ZN9selectors8matching24matches_complex_selector*
...
fun:_ZN69_$LT$style..selector_map..SelectorMap$LT$style..stylist..Rule$GT$$GT$18get_matching_rules*
}
# Conditional jump or move depends on uninitialised value(s)
# at 0x113EFFDE: selectors::matching::matches_complex_selector_internal (option.rs:421)
# by 0x113EFED9: selectors::matching::matches_complex_selector (matching.rs:501)
# by 0x113DFE55: style::stylist::Stylist::match_revalidation_selectors::{{closure}} (matching.rs:397)
{
Bug 1394696 Stylo selector, Sept 2017, part 2
Memcheck:Cond
fun:_ZN9selectors8matching33matches_complex_selector_internal*
fun:_ZN9selectors8matching24matches_complex_selector*
...
fun:_ZN5style9traversal13compute_style*
fun:recalc_style_at<style::gecko::wrapper::GeckoElement,style::gecko::traversal::RecalcStyleOnly,closure>
}
###################################################
# For valgrind-mochitest ("tc-M-V [tier 2]") runs on taskcluster.

View File

@ -112,7 +112,8 @@ def update_nspr_or_nss(tag, depfile, destination, hgpath):
sys.exit(2)
warn_if_patch_exists(permanent_patch_dir)
# protect patch directory from being removed by do_hg_replace
shutil.move(permanent_patch_dir, temporary_patch_dir)
if os.path.exists(permanent_patch_dir):
shutil.move(permanent_patch_dir, temporary_patch_dir)
# now update the destination
print "reverting to HG version of %s to get its blank line state" % depfile
check_call_noisy([options.hg, 'revert', depfile])
@ -127,7 +128,8 @@ def update_nspr_or_nss(tag, depfile, destination, hgpath):
tag_file = destination + "/TAG-INFO"
print >>file(tag_file, "w"), tag
# move patch directory back to a subdirectory
shutil.move(temporary_patch_dir, permanent_patch_dir)
if os.path.exists(temporary_patch_dir):
shutil.move(temporary_patch_dir, permanent_patch_dir)
def warn_if_patch_exists(path):
# If the given patch directory exists and contains at least one file,

View File

@ -14985,55 +14985,56 @@ nsDocShell::ShouldPrepareForIntercept(nsIURI* aURI, bool aIsNonSubresourceReques
return NS_OK;
}
uint32_t cookieBehavior = nsContentUtils::CookiesBehavior();
if (cookieBehavior == nsICookieService::BEHAVIOR_REJECT) {
// If cookies are disabled, don't intercept.
return NS_OK;
}
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (!swm) {
return NS_OK;
}
nsresult result;
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
do_GetService(THIRDPARTYUTIL_CONTRACTID, &result);
NS_ENSURE_SUCCESS(result, result);
if (!aIsNonSubresourceRequest) {
nsCOMPtr<nsIDocument> doc = GetDocument();
if (!doc) {
return NS_ERROR_NOT_AVAILABLE;
}
ErrorResult rv;
*aShouldIntercept = swm->IsControlled(doc, rv);
if (NS_WARN_IF(rv.Failed())) {
return rv.StealNSResult();
}
return NS_OK;
}
// If the user has set a cookie policy that restricts cookies, then
// avoid intercepting 3rd party iframes.
if (cookieBehavior != nsICookieService::BEHAVIOR_ACCEPT) {
nsCOMPtr<nsIDocShellTreeItem> parent;
GetSameTypeParent(getter_AddRefs(parent));
nsCOMPtr<nsPIDOMWindowOuter> parentWindow = parent ? parent->GetWindow()
: nullptr;
if (parentWindow) {
nsresult rv = NS_OK;
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
do_GetService(THIRDPARTYUTIL_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
if (mCurrentURI &&
nsContentUtils::CookiesBehavior() == nsICookieService::BEHAVIOR_REJECT_FOREIGN) {
nsAutoCString uriSpec;
if (!(mCurrentURI->GetSpecOrDefault().EqualsLiteral("about:blank"))) {
// Reject the interception of third-party iframes if the cookie behaviour
// is set to reject all third-party cookies (1). In case that this pref
// is not set or can't be read, we default to allow all cookies (0) as
// this is the default value in all.js.
bool isThirdPartyURI = true;
result = thirdPartyUtil->IsThirdPartyURI(mCurrentURI, aURI,
&isThirdPartyURI);
if (NS_FAILED(result)) {
return result;
}
if (isThirdPartyURI) {
rv = thirdPartyUtil->IsThirdPartyWindow(parentWindow, aURI, &isThirdPartyURI);
if (NS_SUCCEEDED(rv) && isThirdPartyURI) {
return NS_OK;
}
}
}
if (aIsNonSubresourceRequest) {
nsCOMPtr<nsIPrincipal> principal =
BasePrincipal::CreateCodebasePrincipal(aURI, mOriginAttributes);
*aShouldIntercept = swm->IsAvailable(principal, aURI);
return NS_OK;
}
nsCOMPtr<nsIDocument> doc = GetDocument();
if (!doc) {
return NS_ERROR_NOT_AVAILABLE;
}
ErrorResult rv;
*aShouldIntercept = swm->IsControlled(doc, rv);
if (NS_WARN_IF(rv.Failed())) {
return rv.StealNSResult();
}
nsCOMPtr<nsIPrincipal> principal =
BasePrincipal::CreateCodebasePrincipal(aURI, mOriginAttributes);
*aShouldIntercept = swm->IsAvailable(principal, aURI);
return NS_OK;
}

View File

@ -9060,6 +9060,20 @@ nsContentUtils::StorageAllowedForWindow(nsPIDOMWindowInner* aWindow)
return StorageAccess::eDeny;
}
// static, public
nsContentUtils::StorageAccess
nsContentUtils::StorageAllowedForDocument(nsIDocument* aDoc)
{
MOZ_ASSERT(aDoc);
if (nsPIDOMWindowInner* inner = aDoc->GetInnerWindow()) {
nsCOMPtr<nsIPrincipal> principal = aDoc->NodePrincipal();
return InternalStorageAllowedForPrincipal(principal, inner);
}
return StorageAccess::eDeny;
}
// static, public
nsContentUtils::StorageAccess
nsContentUtils::StorageAllowedForPrincipal(nsIPrincipal* aPrincipal)
@ -9139,7 +9153,7 @@ nsContentUtils::InternalStorageAllowedForPrincipal(nsIPrincipal* aPrincipal,
if (aWindow) {
// If the document is sandboxed, then it is not permitted to use storage
nsIDocument* document = aWindow->GetExtantDoc();
if (document->GetSandboxFlags() & SANDBOXED_ORIGIN) {
if (document && document->GetSandboxFlags() & SANDBOXED_ORIGIN) {
return StorageAccess::eDeny;
}

View File

@ -2925,6 +2925,17 @@ public:
*/
static StorageAccess StorageAllowedForWindow(nsPIDOMWindowInner* aWindow);
/*
* Checks if storage for the given document is permitted by a combination of
* the user's preferences, and whether the document's window is a third-party
* iframe.
*
* Note, this may be used on documents during the loading process where
* the window's extant document has not been set yet. The code in
* StorageAllowedForWindow(), however, will not work in these cases.
*/
static StorageAccess StorageAllowedForDocument(nsIDocument* aDoc);
/*
* Checks if storage for the given principal is permitted by the user's
* preferences. The caller is assumed to not be a third-party iframe.

View File

@ -51,3 +51,4 @@ scheme=https
[test_chrome_constructor.html]
[test_cache_worker_gc.html]
scheme=https
[test_cache_tons_of_fd.html]

View File

@ -0,0 +1,111 @@
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<!DOCTYPE HTML>
<html>
<head>
<title>Test cache to create tons of fds</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript" src="driver.js"></script>
</head>
<body>
<script class="testbody" type="text/javascript">
function setupTestIframe() {
return new Promise(function(resolve) {
var iframe = document.createElement("iframe");
iframe.src = "empty.html";
iframe.onload = function() {
window.caches = iframe.contentWindow.caches;
resolve();
};
document.body.appendChild(iframe);
});
}
function clearStorage() {
return new Promise(function(resolve, reject) {
var qms = SpecialPowers.Services.qms;
var principal = SpecialPowers.wrap(document).nodePrincipal;
var request = qms.clearStoragesForPrincipal(principal);
var cb = SpecialPowers.wrapCallback(resolve);
request.callback = cb;
});
}
async function testCreateTonsOfFD() {
const number_of_fd = 5120;
const name = 'cacheTonsOfFD';
const url = "foo.com"
const body = "This is a body";
info("Stage A: Cached a Request/Response pairs");
let cache = await caches.open(name);
let request = new Request(url);
let response = new Response(body);
await cache.put(request, response);
info("Stage B: Read the cached response mutliple times");
let promise_array = [];
for (let i = 0; i < number_of_fd; ++i) {
let promise = cache.match(request);
promise_array.push(promise);
}
let cached_response_array = [];
try {
cached_response_array = await Promise.all(promise_array);
} catch (e) {
throw("Fail to open tons of files with error: " + e);
}
if (cached_response_array.length != number_of_fd) {
throw("Fail to cache.match the cached responses");
}
info("Stage C: Consume the cached body")
for (let i = 0; i < number_of_fd; ++i) {
if (!cached_response_array[i]) {
// Reduce the checking message.
throw("The cached response doesn't exist");
}
let bodyText = "";
try {
bodyText = await cached_response_array[i].text();
} catch (e) {
throw("Fail to consume the cached response's body with error: " + e);
}
if (bodyText != body) {
// Reduce the checking message.
throw("The cached body doeen't be the same as original one");
}
}
ok(true, "Doesn't crash or timeout");
return Promise.resolve();
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({
"set": [["dom.caches.enabled", true],
["dom.caches.testing.enabled", true],
["dom.quotaManager.testing", true]]
}, async function() {
await setupTestIframe();
info("Stage 1: Clean storage.");
await clearStorage();
info("Stage 2: Verify open lots of files at the same time doesn't crash " +
"the browser");
try {
await testCreateTonsOfFD();
} catch (e) {
ok(false, e);
}
await SimpleTest.finish();
});
</script>
</body>
</html>

View File

@ -695,7 +695,10 @@ IDBDatabase::Transaction(JSContext* aCx,
RefPtr<IDBTransaction> transaction =
IDBTransaction::Create(aCx, this, sortedStoreNames, mode);
MOZ_ASSERT(transaction);
if (NS_WARN_IF(!transaction)) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
BackgroundTransactionChild* actor =
new BackgroundTransactionChild(transaction);

View File

@ -230,6 +230,21 @@ IDBTransaction::Create(JSContext* aCx, IDBDatabase* aDatabase,
transaction->SetScriptOwner(aDatabase->GetScriptOwner());
if (!NS_IsMainThread()) {
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
workerPrivate->AssertIsOnWorkerThread();
nsAutoPtr<WorkerHolder> workerHolder(
new WorkerHolder(workerPrivate, transaction));
if (NS_WARN_IF(!workerHolder->HoldWorker(workerPrivate, Canceling))) {
return nullptr;
}
transaction->mWorkerHolder = Move(workerHolder);
}
nsCOMPtr<nsIRunnable> runnable = do_QueryObject(transaction);
nsContentUtils::RunInMetastableState(runnable.forget());
@ -238,16 +253,6 @@ IDBTransaction::Create(JSContext* aCx, IDBDatabase* aDatabase,
aDatabase->RegisterTransaction(transaction);
transaction->mRegistered = true;
if (!NS_IsMainThread()) {
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
workerPrivate->AssertIsOnWorkerThread();
transaction->mWorkerHolder = new WorkerHolder(workerPrivate, transaction);
MOZ_ALWAYS_TRUE(transaction->mWorkerHolder->HoldWorker(workerPrivate, Canceling));
}
return transaction.forget();
}

View File

@ -93,6 +93,12 @@ ServiceWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
return;
}
auto storageAllowed = nsContentUtils::StorageAllowedForWindow(window);
if (storageAllowed != nsContentUtils::StorageAccess::eAllow) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
UniquePtr<ServiceWorkerClientInfo> clientInfo(new ServiceWorkerClientInfo(window->GetExtantDoc()));
ServiceWorkerPrivate* workerPrivate = mInfo->WorkerPrivate();
aRv = workerPrivate->SendMessageEvent(aCx, aMessage, aTransferable, Move(clientInfo));

View File

@ -828,11 +828,17 @@ ServiceWorkerManager::Register(mozIDOMWindow* aWindow,
}
auto* window = nsPIDOMWindowInner::From(aWindow);
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
if (!doc) {
return NS_ERROR_FAILURE;
// Don't allow a service worker to be registered if storage is restricted
// for the window.
auto storageAllowed = nsContentUtils::StorageAllowedForWindow(window);
if (storageAllowed != nsContentUtils::StorageAccess::eAllow) {
return NS_ERROR_DOM_SECURITY_ERR;
}
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
MOZ_ASSERT(doc);
// Don't allow service workers to register when the *document* is chrome.
if (NS_WARN_IF(nsContentUtils::IsSystemPrincipal(doc->NodePrincipal()))) {
return NS_ERROR_DOM_SECURITY_ERR;
@ -1074,14 +1080,19 @@ ServiceWorkerManager::GetRegistrations(mozIDOMWindow* aWindow,
}
auto* window = nsPIDOMWindowInner::From(aWindow);
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
if (NS_WARN_IF(!doc)) {
return NS_ERROR_DOM_INVALID_STATE_ERR;
// Don't allow a service worker to access service worker registrations
// from a window with storage disabled. If these windows can access
// the registration it increases the chance they can bypass the storage
// block via postMessage(), etc.
auto storageAllowed = nsContentUtils::StorageAllowedForWindow(window);
if (storageAllowed != nsContentUtils::StorageAccess::eAllow) {
return NS_ERROR_DOM_SECURITY_ERR;
}
// Don't allow service workers to register when the *document* is chrome for
// now.
MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(doc->NodePrincipal()));
MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(window->GetExtantDoc()->NodePrincipal()));
nsCOMPtr<nsIGlobalObject> sgo = do_QueryInterface(window);
ErrorResult result;
@ -1187,14 +1198,19 @@ ServiceWorkerManager::GetRegistration(mozIDOMWindow* aWindow,
}
auto* window = nsPIDOMWindowInner::From(aWindow);
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
if (NS_WARN_IF(!doc)) {
return NS_ERROR_DOM_INVALID_STATE_ERR;
// Don't allow a service worker to access service worker registrations
// from a window with storage disabled. If these windows can access
// the registration it increases the chance they can bypass the storage
// block via postMessage(), etc.
auto storageAllowed = nsContentUtils::StorageAllowedForWindow(window);
if (storageAllowed != nsContentUtils::StorageAccess::eAllow) {
return NS_ERROR_DOM_SECURITY_ERR;
}
// Don't allow service workers to register when the *document* is chrome for
// now.
MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(doc->NodePrincipal()));
MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(window->GetExtantDoc()->NodePrincipal()));
nsCOMPtr<nsIGlobalObject> sgo = do_QueryInterface(window);
ErrorResult result;
@ -2178,7 +2194,15 @@ ServiceWorkerManager::GetServiceWorkerRegistrationInfo(nsIDocument* aDoc)
MOZ_ASSERT(aDoc);
nsCOMPtr<nsIURI> documentURI = aDoc->GetDocumentURI();
nsCOMPtr<nsIPrincipal> principal = aDoc->NodePrincipal();
return GetServiceWorkerRegistrationInfo(principal, documentURI);
RefPtr<ServiceWorkerRegistrationInfo> reg =
GetServiceWorkerRegistrationInfo(principal, documentURI);
if (reg) {
auto storageAllowed = nsContentUtils::StorageAllowedForDocument(aDoc);
if (storageAllowed != nsContentUtils::StorageAccess::eAllow) {
reg = nullptr;
}
}
return reg.forget();
}
already_AddRefed<ServiceWorkerRegistrationInfo>
@ -2471,6 +2495,11 @@ ServiceWorkerManager::StartControllingADocument(ServiceWorkerRegistrationInfo* a
MOZ_ASSERT(aRegistration);
MOZ_ASSERT(aDoc);
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
auto storageAllowed = nsContentUtils::StorageAllowedForDocument(aDoc);
MOZ_DIAGNOSTIC_ASSERT(storageAllowed == nsContentUtils::StorageAccess::eAllow);
#endif // MOZ_DIAGNOSTIC_ASSERT_ENABLED
aRegistration->StartControllingADocument();
mControlledDocuments.Put(aDoc, aRegistration);
if (!aDocumentId.IsEmpty()) {
@ -3281,7 +3310,7 @@ ServiceWorkerManager::GetClient(nsIPrincipal* aPrincipal,
nsCOMPtr<nsISupports> ptr;
ifptr->GetData(getter_AddRefs(ptr));
nsCOMPtr<nsIDocument> doc = do_QueryInterface(ptr);
if (NS_WARN_IF(!doc)) {
if (NS_WARN_IF(!doc || !doc->GetInnerWindow())) {
return clientInfo;
}
@ -3296,6 +3325,14 @@ ServiceWorkerManager::GetClient(nsIPrincipal* aPrincipal,
return clientInfo;
}
// Don't let service worker see 3rd party iframes that are denied storage
// access. We don't want these to communicate.
auto storageAccess =
nsContentUtils::StorageAllowedForWindow(doc->GetInnerWindow());
if (storageAccess != nsContentUtils::StorageAccess::eAllow) {
return clientInfo;
}
clientInfo.reset(new ServiceWorkerClientInfo(doc));
return clientInfo;
}
@ -3340,7 +3377,7 @@ ServiceWorkerManager::GetAllClients(nsIPrincipal* aPrincipal,
}
nsCOMPtr<nsIDocument> doc = do_QueryInterface(ptr);
if (!doc || !doc->GetWindow()) {
if (!doc || !doc->GetWindow() || !doc->GetInnerWindow()) {
continue;
}
@ -3358,6 +3395,14 @@ ServiceWorkerManager::GetAllClients(nsIPrincipal* aPrincipal,
continue;
}
// Don't let service worker find 3rd party iframes that are denied storage
// access. We don't want these to communicate.
auto storageAccess =
nsContentUtils::StorageAllowedForWindow(doc->GetInnerWindow());
if (storageAccess != nsContentUtils::StorageAccess::eAllow) {
continue;
}
// If we are only returning controlled Clients then skip any documents
// that are for different registrations. We also skip service workers
// that don't match the ID of our calling service worker. We should

View File

@ -180,6 +180,7 @@ support-files =
thirdparty/register.html
thirdparty/unregister.html
thirdparty/sw.js
thirdparty/worker.js
register_https.html
gzip_redirect_worker.js
sw_clients/navigator.html
@ -238,6 +239,8 @@ skip-if = debug # Bug 1262224
[test_eventsource_intercept.html]
[test_fetch_event.html]
skip-if = (debug && e10s) # Bug 1262224
[test_fetch_event_with_thirdpartypref.html]
skip-if = (debug && e10s) # Bug 1262224
[test_fetch_integrity.html]
[test_file_blob_response.html]
[test_file_blob_upload.html]

View File

@ -0,0 +1,93 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 94048 - test install event.</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
<script src="utils.js"></script>
<script class="testbody" type="text/javascript">
// NOTE: This is just test_fetch_event.html but with an alternate cookie
// mode preference set to make sure that setting the preference does
// not break interception as observed in bug 1336364.
// TODO: Refactor this test so it doesn't duplicate so much code logic.
SimpleTest.requestCompleteLog();
var registration;
function simpleRegister() {
return navigator.serviceWorker.register("fetch_event_worker.js", { scope: "./fetch" })
.then(swr => {
registration = swr;
return waitForState(swr.installing, 'activated');
});
}
function unregister() {
return registration.unregister().then(function(success) {
ok(success, "Service worker should be unregistered successfully");
}, function(e) {
dump("SW unregistration error: " + e + "\n");
});
}
function testController() {
var p = new Promise(function(resolve, reject) {
var reloaded = false;
window.onmessage = function(e) {
if (e.data.status == "ok") {
ok(e.data.result, e.data.message);
} else if (e.data.status == "done") {
if (reloaded) {
window.onmessage = null;
w.close();
resolve();
} else {
w.location.reload();
reloaded = true;
}
}
}
});
var w = window.open("fetch/index.html");
return p;
}
function runTest() {
simpleRegister()
.then(testController)
.then(unregister)
.then(function() {
SimpleTest.finish();
}).catch(function(e) {
ok(false, "Some test failed with error " + e);
SimpleTest.finish();
});
}
const COOKIE_BEHAVIOR_REJECTFOREIGN = 1;
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true],
["javascript.options.streams", true],
["network.cookie.cookieBehavior", COOKIE_BEHAVIOR_REJECTFOREIGN],
["dom.streams.enabled", true],
]}, runTest);
</script>
</pre>
</body>
</html>

View File

@ -80,58 +80,128 @@ function runTest(aExpectedResponses) {
};
}
function testShouldIntercept(done) {
runTest([{
status: "ok"
}, {
status: "registrationdone",
next: function() {
iframe.addEventListener("load", testIframeLoaded);
iframe.src = origin + basePath + "iframe1.html";
}
}, {
status: "networkresponse",
next: loadThirdPartyIframe
}, {
status: "swresponse",
next: function() {
iframe.src = thirdPartyOrigin + basePath + "unregister.html";
}
}, {
status: "unregistrationdone",
next: function() {
window.onmessage = null;
ok(true, "Test finished successfully");
done();
}
}]);
// Verify that we can register and intercept a 3rd party iframe with
// the given cookie policy.
function testShouldIntercept(policy, done) {
SpecialPowers.pushPrefEnv({"set": [
["network.cookie.cookieBehavior", policy]
]}, function() {
runTest([{
status: "ok"
}, {
status: "registrationdone",
next: function() {
iframe.addEventListener("load", testIframeLoaded);
iframe.src = origin + basePath + "iframe1.html";
}
}, {
status: "networkresponse",
}, {
status: "worker-networkresponse",
next: loadThirdPartyIframe
}, {
status: "swresponse",
}, {
status: "worker-swresponse",
next: function() {
iframe.src = thirdPartyOrigin + basePath + "unregister.html";
}
}, {
status: "controlled",
}, {
status: "unregistrationdone",
next: function() {
window.onmessage = null;
ok(true, "Test finished successfully");
done();
}
}]);
});
}
function testShouldNotIntercept(done) {
runTest([{
status: "ok"
}, {
status: "registrationdone",
next: function() {
iframe.addEventListener("load", testIframeLoaded);
iframe.src = origin + basePath + "iframe1.html";
}
}, {
status: "networkresponse",
next: loadThirdPartyIframe
}, {
status: "networkresponse",
next: function() {
iframe.src = thirdPartyOrigin + basePath + "unregister.html";
}
}, {
status: "unregistrationdone",
next: function() {
window.onmessage = null;
ok(true, "Test finished successfully");
done();
}
}]);
// Verify that we cannot register a service worker in a 3rd party
// iframe with the given cookie policy.
function testShouldNotRegister(policy, done) {
SpecialPowers.pushPrefEnv({"set": [
["network.cookie.cookieBehavior", policy]
]}, function() {
runTest([{
status: "registrationfailed",
next: function() {
iframe.addEventListener("load", testIframeLoaded);
iframe.src = origin + basePath + "iframe1.html";
}
}, {
status: "networkresponse",
}, {
status: "worker-networkresponse",
next: loadThirdPartyIframe
}, {
status: "networkresponse",
}, {
status: "worker-networkresponse",
next: function() {
window.onmessage = null;
ok(true, "Test finished successfully");
done();
}
}]);
});
}
// Verify that if a service worker is already registered a 3rd
// party iframe will still not be intercepted with the given cookie
// policy.
function testShouldNotIntercept(policy, done) {
SpecialPowers.pushPrefEnv({"set": [
["network.cookie.cookieBehavior", COOKIE_BEHAVIOR_ACCEPT]
]}, function() {
runTest([{
status: "ok"
}, {
status: "registrationdone",
next: function() {
iframe.addEventListener("load", testIframeLoaded);
SpecialPowers.pushPrefEnv({"set": [
["network.cookie.cookieBehavior", policy],
]}, function() {
iframe.src = origin + basePath + "iframe1.html";
});
}
}, {
status: "networkresponse",
}, {
status: "worker-networkresponse",
next: loadThirdPartyIframe
}, {
status: "networkresponse",
}, {
status: "worker-networkresponse",
next: function() {
iframe.src = thirdPartyOrigin + basePath + "unregister.html";
}
}, {
status: "uncontrolled",
}, {
status: "getregistrationfailed",
next: function() {
SpecialPowers.pushPrefEnv({"set": [
["network.cookie.cookieBehavior", COOKIE_BEHAVIOR_ACCEPT],
]}, function() {
iframe.src = thirdPartyOrigin + basePath + "unregister.html";
});
}
}, {
status: "controlled",
}, {
status: "unregistrationdone",
next: function() {
window.onmessage = null;
ok(true, "Test finished successfully");
done();
}
}]);
});
}
const COOKIE_BEHAVIOR_ACCEPT = 0;
@ -148,25 +218,19 @@ let steps = [() => {
["network.cookie.cookieBehavior", COOKIE_BEHAVIOR_ACCEPT]
]}, next);
}, () => {
testShouldIntercept(next);
testShouldIntercept(COOKIE_BEHAVIOR_ACCEPT, next);
}, () => {
SpecialPowers.pushPrefEnv({"set": [
["network.cookie.cookieBehavior", COOKIE_BEHAVIOR_REJECTFOREIGN]
]}, next);
testShouldNotRegister(COOKIE_BEHAVIOR_REJECTFOREIGN, next);
}, () => {
testShouldNotIntercept(next);
testShouldNotIntercept(COOKIE_BEHAVIOR_REJECTFOREIGN, next);
}, () => {
SpecialPowers.pushPrefEnv({"set": [
["network.cookie.cookieBehavior", COOKIE_BEHAVIOR_REJECT]
]}, next);
testShouldNotRegister(COOKIE_BEHAVIOR_REJECT, next);
}, () => {
testShouldIntercept(next);
testShouldNotIntercept(COOKIE_BEHAVIOR_REJECT, next);
}, () => {
SpecialPowers.pushPrefEnv({"set": [
["network.cookie.cookieBehavior", COOKIE_BEHAVIOR_LIMITFOREIGN]
]}, next);
testShouldNotRegister(COOKIE_BEHAVIOR_LIMITFOREIGN, next);
}, () => {
testShouldIntercept(next);
testShouldNotIntercept(COOKIE_BEHAVIOR_LIMITFOREIGN, next);
}];
</script>

View File

@ -17,6 +17,8 @@
}
else if (message.source == "iframe") {
parent.postMessage(event.data, "*");
} else if (message.source == "worker") {
parent.postMessage(event.data, "*");
}
}
</script>

View File

@ -4,4 +4,11 @@
source: "iframe",
status: "networkresponse"
}, "*");
var w = new Worker('worker.js');
w.onmessage = function(evt) {
window.parent.postMessage({
source: 'worker',
status: evt.data,
}, '*');
};
</script>

View File

@ -23,5 +23,7 @@
} else {
done(registration);
}
}).catch(function(e) {
window.parent.postMessage({status: "registrationfailed"}, "*");
});
</script>

View File

@ -1,14 +1,29 @@
self.addEventListener("fetch", function(event) {
dump("fetch " + event.request.url + "\n");
if (event.request.url.indexOf("iframe2.html") >= 0) {
if (event.request.url.includes("iframe2.html")) {
var body =
"<script>" +
"window.parent.postMessage({" +
"source: 'iframe', status: 'swresponse'" +
"}, '*');" +
"var w = new Worker('worker.js');" +
"w.onmessage = function(evt) {" +
"window.parent.postMessage({" +
"source: 'worker'," +
"status: evt.data," +
"}, '*');" +
"};" +
"</script>";
event.respondWith(new Response(body, {
headers: {'Content-Type': 'text/html'}
}));
return;
}
if (event.request.url.includes("worker.js")) {
var body = "self.postMessage('worker-swresponse');";
event.respondWith(new Response(body, {
headers: {'Content-Type': 'application/javascript'}
}));
return;
}
});

View File

@ -1,5 +1,11 @@
<!DOCTYPE html>
<script>
if (navigator.serviceWorker.controller) {
window.parent.postMessage({status: "controlled"}, "*");
} else {
window.parent.postMessage({status: "uncontrolled"}, "*");
}
navigator.serviceWorker.getRegistration(".").then(function(registration) {
if(!registration) {
return;
@ -7,5 +13,7 @@
registration.unregister().then(() => {
window.parent.postMessage({status: "unregistrationdone"}, "*");
});
}).catch(function(e) {
window.parent.postMessage({status: "getregistrationfailed"}, "*");
});
</script>

View File

@ -0,0 +1 @@
self.postMessage('worker-networkresponse');

View File

@ -2743,13 +2743,14 @@ EditorBase::SetTextImpl(Selection& aSelection, const nsAString& aString,
return rv;
}
// Only set selection to insertion point if editor gives permission
if (GetShouldTxnSetSelection()) {
{
// Create a nested scope to not overwrite rv from the outer scope.
RefPtr<Selection> selection = GetSelection();
DebugOnly<nsresult> rv = selection->Collapse(&aCharData, length);
DebugOnly<nsresult> rv = selection->Collapse(&aCharData, aString.Length());
NS_ASSERTION(NS_SUCCEEDED(rv),
"Selection could not be collapsed after insert");
}
mRangeUpdater.SelAdjDeleteText(&aCharData, 0, length);
mRangeUpdater.SelAdjInsertText(aCharData, 0, aString);

View File

@ -873,9 +873,6 @@ TextEditRules::WillSetText(Selection& aSelection,
return NS_OK;
}
// don't change my selection in subtransactions
AutoTransactionsConserveSelection dontChangeMySelection(textEditor);
// Even if empty text, we don't remove text node and set empty text
// for performance
nsresult rv = textEditor->SetTextImpl(aSelection, tString,

View File

@ -253,6 +253,7 @@ skip-if = toolkit == 'android' # bug 1315898
[test_bug1368544.html]
[test_bug1385905.html]
[test_bug1394758.html]
[test_bug1399722.html]
[test_CF_HTML_clipboard.html]
subsuite = clipboard

View File

@ -0,0 +1,40 @@
<!DOCTYPE html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1399722
-->
<html>
<head>
<title>Test for Bug 1399722</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1399722">Mozilla Bug 1399722</a>
<p id="display"></p>
<div id="content" style="display: none;">
</div>
<input spellcheck="true" onkeypress="if (event.key=='Enter')this.value='';">
<pre id="test">
<script class="testbody" type="application/javascript">
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(function() {
let elm = document.querySelector("input");
elm.focus();
synthesizeKey("A", {});
synthesizeKey("B", {});
synthesizeKey("KEY_Enter", {});
synthesizeKey("C", {});
synthesizeKey("D", {});
is(elm.value, "CD", "Can type into the textbox successfully after the onkeypress handler deleting the value");
SimpleTest.finish();
});
</script>
</pre>
</body>
</html>

View File

@ -238,8 +238,7 @@ DrawTargetD2D1::DrawSurface(SourceSurface *aSurface,
mDC->FillRectangle(D2DRect(aDest), brush);
}
Rect destBounds = mTransform.TransformBounds(aDest);
FinalizeDrawing(aOptions.mCompositionOp, ColorPattern(Color()), &destBounds);
FinalizeDrawing(aOptions.mCompositionOp, ColorPattern(Color()));
}
void
@ -1345,7 +1344,7 @@ DrawTargetD2D1::PrepareForDrawing(CompositionOp aOp, const Pattern &aPattern)
}
void
DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern, const Rect* aAffectedRect /* = nullptr */)
DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern)
{
bool patternSupported = IsPatternSupportedByD2D(aPattern);
@ -1408,25 +1407,15 @@ DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern, cons
return;
}
Point outOffset;
// We don't need to preserve the current content of this layer if the output
// We don't need to preserve the current content of this layer as the output
// of the blend effect should completely replace it.
bool shouldPreserveContent = !!aAffectedRect && !aAffectedRect->Contains(Rect(0, 0, mSize.width, mSize.height));
RefPtr<ID2D1Image> tmpImage = GetImageForLayerContent(shouldPreserveContent, aAffectedRect, &outOffset);
RefPtr<ID2D1Image> tmpImage = GetImageForLayerContent(false);
if (!tmpImage) {
return;
}
blendEffect->SetInput(0, tmpImage);
blendEffect->SetInput(1, source);
if (outOffset != Point()) {
RefPtr<ID2D1Effect> transformEffect;
mDC->CreateEffect(CLSID_D2D12DAffineTransform, getter_AddRefs(transformEffect));
transformEffect->SetInput(0, tmpImage);
transformEffect->SetValue(D2D1_2DAFFINETRANSFORM_PROP_TRANSFORM_MATRIX, D2D1::Matrix3x2F::Translation(outOffset.x, outOffset.y));
blendEffect->SetInputEffect(0, transformEffect);
}
blendEffect->SetValue(D2D1_BLEND_PROP_MODE, D2DBlendMode(aOp));
mDC->DrawImage(blendEffect, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_BOUNDED_SOURCE_COPY);
@ -1518,14 +1507,10 @@ DrawTargetD2D1::GetDeviceSpaceClipRect(D2D1_RECT_F& aClipRect, bool& aIsPixelAli
}
already_AddRefed<ID2D1Image>
DrawTargetD2D1::GetImageForLayerContent(bool aShouldPreserveContent, const Rect* aBounds /* = nullptr */, Point* aOutOffset /* = nullptr */)
DrawTargetD2D1::GetImageForLayerContent(bool aShouldPreserveContent)
{
PopAllClips();
if (aOutOffset) {
*aOutOffset = Point();
}
if (!CurrentLayer().mCurrentList) {
RefPtr<ID2D1Bitmap> tmpBitmap;
HRESULT hr = mDC->CreateBitmap(D2DIntSize(mSize), D2D1::BitmapProperties(D2DPixelFormat(mFormat)), getter_AddRefs(tmpBitmap));
@ -1555,20 +1540,10 @@ DrawTargetD2D1::GetImageForLayerContent(bool aShouldPreserveContent, const Rect*
D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_TARGET,
D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM,
D2D1_ALPHA_MODE_PREMULTIPLIED));
D2D1_SIZE_U size = mBitmap->GetPixelSize();
D2D1_POINT_2F offset = D2D1::Point2F();
if (aBounds) {
size.width = aBounds->width;
size.height = aBounds->height;
offset.x = -aBounds->x;
offset.y = -aBounds->y;
aOutOffset->x = aBounds->x;
aOutOffset->y = aBounds->y;
}
mDC->CreateBitmap(size, nullptr, 0, &props, getter_AddRefs(tmpBitmap));
mDC->CreateBitmap(mBitmap->GetPixelSize(), nullptr, 0, &props, getter_AddRefs(tmpBitmap));
mDC->SetTransform(D2D1::IdentityMatrix());
mDC->SetTarget(tmpBitmap);
mDC->DrawImage(list, offset, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_BOUNDED_SOURCE_COPY);
mDC->DrawImage(list, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_BOUNDED_SOURCE_COPY);
mDC->SetTarget(CurrentTarget());
}

View File

@ -180,9 +180,7 @@ private:
void MarkChanged();
bool ShouldClipTemporarySurfaceDrawing(CompositionOp aOp, const Pattern& aPattern, bool aClipIsComplex);
void PrepareForDrawing(CompositionOp aOp, const Pattern &aPattern);
// aAffectedRect may be used to supply the bounds of the drawing operations in order to prevent
// excessive surface area being operated on
void FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern, const Rect* aAffectedRect = nullptr);
void FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern);
void FlushTransformToDC() {
if (mTransformDirty) {
mDC->SetTransform(D2DMatrix(mTransform));
@ -192,11 +190,7 @@ private:
void AddDependencyOnSource(SourceSurfaceD2D1* aSource);
// Must be called with all clips popped and an identity matrix set.
// aBounds can be specified to allow the function to return only part of the layer contents
// aOutOffset will return the offset that should be applied to move the ID2D1Image onto the
// correct portion of the destination layer. If !aBounds this will always be 0,0 and can be
// ignored.
already_AddRefed<ID2D1Image> GetImageForLayerContent(bool aShouldPreserveContent = true, const Rect* aBounds = nullptr, Point* aOutOffset = nullptr);
already_AddRefed<ID2D1Image> GetImageForLayerContent(bool aShouldPreserveContent = true);
ID2D1Image* CurrentTarget()
{

View File

@ -64,6 +64,7 @@ ImageBridgeParent::ImageBridgeParent(MessageLoop* aLoop,
: mMessageLoop(aLoop)
, mSetChildThreadPriority(false)
, mClosed(false)
, mCompositorThreadHolder(CompositorThreadHolder::GetSingleton())
{
MOZ_ASSERT(NS_IsMainThread());
@ -364,13 +365,6 @@ ImageBridgeParent::GetInstance(ProcessId aId)
return sImageBridges[aId];
}
void
ImageBridgeParent::OnChannelConnected(int32_t aPid)
{
mCompositorThreadHolder = GetCompositorThreadHolder();
}
bool
ImageBridgeParent::AllocShmem(size_t aSize,
ipc::SharedMemory::SharedMemoryType aType,

View File

@ -122,8 +122,6 @@ public:
virtual bool IPCOpen() const override { return !mClosed; }
protected:
void OnChannelConnected(int32_t pid) override;
void Bind(Endpoint<PImageBridgeParent>&& aEndpoint);
private:

View File

@ -51,14 +51,14 @@ parent:
async SetDisplayList(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
LayoutSize aContentSize, ByteBuffer aDL, BuiltDisplayListDescriptor aDLDesc,
WebRenderScrollData aScrollData,
OpUpdateResource[] aResourceUpdates, Shmem[] aResourceData,
OpUpdateResource[] aResourceUpdates, Shmem[] aSmallShmems, Shmem[] aLargeShmems,
IdNamespace aIdNamespace, TimeStamp txnStartTime, TimeStamp fwdTime);
sync SetDisplayListSync(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
LayoutSize aContentSize, ByteBuffer aDL, BuiltDisplayListDescriptor aDLDesc,
WebRenderScrollData aScrollData,
OpUpdateResource[] aResourceUpdates, Shmem[] aResourceData,
OpUpdateResource[] aResourceUpdates, Shmem[] aSmallShmems, Shmem[] aLargeShmems,
IdNamespace aIdNamespace, TimeStamp txnStartTime, TimeStamp fwdTime);
async UpdateResources(OpUpdateResource[] aResourceUpdates, Shmem[] aResourceData);
async UpdateResources(OpUpdateResource[] aResourceUpdates, Shmem[] aSmallShmems, Shmem[] aLargeShmems);
async ParentCommands(WebRenderParentCommand[] commands);
sync GetSnapshot(PTexture texture);
async AddPipelineIdForCompositable(PipelineId aImageId, CompositableHandle aHandle, bool aAsync);

View File

@ -62,13 +62,13 @@ struct OpUpdateAsyncImagePipeline {
};
union WebRenderParentCommand {
OpAddExternalImage;
OpUpdateAsyncImagePipeline;
CompositableOperation;
OpAddCompositorAnimations;
};
struct OffsetRange {
uint32_t source;
uint32_t start;
uint32_t length;
};
@ -135,6 +135,7 @@ union OpUpdateResource {
OpDeleteFont;
OpAddFontInstance;
OpDeleteFontInstance;
OpAddExternalImage;
};
} // namespace

View File

@ -30,19 +30,26 @@ ShmSegmentsWriter::Write(Range<uint8_t> aBytes)
const size_t start = mCursor;
const size_t length = aBytes.length();
if (length >= mChunkSize * 4) {
auto range = AllocLargeChunk(length);
uint8_t* dstPtr = mLargeAllocs.LastElement().get<uint8_t>();
memcpy(dstPtr, aBytes.begin().get(), length);
return range;
}
int remainingBytesToCopy = length;
size_t srcCursor = 0;
size_t dstCursor = mCursor;
while (remainingBytesToCopy > 0) {
if (dstCursor >= mData.Length() * mChunkSize) {
if (dstCursor >= mSmallAllocs.Length() * mChunkSize) {
AllocChunk();
continue;
}
const size_t dstMaxOffset = mChunkSize * mData.Length();
const size_t dstBaseOffset = mChunkSize * (mData.Length() - 1);
const size_t dstMaxOffset = mChunkSize * mSmallAllocs.Length();
const size_t dstBaseOffset = mChunkSize * (mSmallAllocs.Length() - 1);
MOZ_ASSERT(dstCursor >= dstBaseOffset);
MOZ_ASSERT(dstCursor <= dstMaxOffset);
@ -51,7 +58,7 @@ ShmSegmentsWriter::Write(Range<uint8_t> aBytes)
size_t copyRange = std::min<int>(availableRange, remainingBytesToCopy);
uint8_t* srcPtr = &aBytes[srcCursor];
uint8_t* dstPtr = mData.LastElement().get<uint8_t>() + (dstCursor - dstBaseOffset);
uint8_t* dstPtr = mSmallAllocs.LastElement().get<uint8_t>() + (dstCursor - dstBaseOffset);
memcpy(dstPtr, srcPtr, copyRange);
@ -65,7 +72,7 @@ ShmSegmentsWriter::Write(Range<uint8_t> aBytes)
mCursor += length;
return layers::OffsetRange(start, length);
return layers::OffsetRange(0, start, length);
}
void
@ -74,44 +81,67 @@ ShmSegmentsWriter::AllocChunk()
ipc::Shmem shm;
auto shmType = ipc::SharedMemory::SharedMemoryType::TYPE_BASIC;
if (!mShmAllocator->AllocShmem(mChunkSize, shmType, &shm)) {
MOZ_CRASH("Shared memory allocation failed");
gfxCriticalError() << "ShmSegmentsWriter failed to allocate chunk #" << mSmallAllocs.Length();
MOZ_CRASH();
}
mData.AppendElement(shm);
mSmallAllocs.AppendElement(shm);
}
layers::OffsetRange
ShmSegmentsWriter::AllocLargeChunk(size_t aSize)
{
ipc::Shmem shm;
auto shmType = ipc::SharedMemory::SharedMemoryType::TYPE_BASIC;
if (!mShmAllocator->AllocShmem(aSize, shmType, &shm)) {
gfxCriticalError() << "ShmSegmentsWriter failed to allocate large chunk of size " << aSize;
MOZ_CRASH();
}
mLargeAllocs.AppendElement(shm);
return layers::OffsetRange(mLargeAllocs.Length(), 0, aSize);
}
void
ShmSegmentsWriter::Flush(nsTArray<ipc::Shmem>& aInto)
ShmSegmentsWriter::Flush(nsTArray<ipc::Shmem>& aSmallAllocs, nsTArray<ipc::Shmem>& aLargeAllocs)
{
aInto.Clear();
mData.SwapElements(aInto);
aSmallAllocs.Clear();
aLargeAllocs.Clear();
mSmallAllocs.SwapElements(aSmallAllocs);
mLargeAllocs.SwapElements(aLargeAllocs);
}
void
ShmSegmentsWriter::Clear()
{
if (mShmAllocator) {
for (auto& shm : mData) {
for (auto& shm : mSmallAllocs) {
mShmAllocator->DeallocShmem(shm);
}
for (auto& shm : mLargeAllocs) {
mShmAllocator->DeallocShmem(shm);
}
}
mData.Clear();
mSmallAllocs.Clear();
mLargeAllocs.Clear();
mCursor = 0;
}
ShmSegmentsReader::ShmSegmentsReader(const nsTArray<ipc::Shmem>& aShmems)
: mData(aShmems)
ShmSegmentsReader::ShmSegmentsReader(const nsTArray<ipc::Shmem>& aSmallShmems,
const nsTArray<ipc::Shmem>& aLargeShmems)
: mSmallAllocs(aSmallShmems)
, mLargeAllocs(aLargeShmems)
, mChunkSize(0)
{
if (mData.IsEmpty()) {
if (mSmallAllocs.IsEmpty()) {
return;
}
mChunkSize = mData[0].Size<uint8_t>();
mChunkSize = mSmallAllocs[0].Size<uint8_t>();
// Check that all shmems are readable and have the same size. If anything
// isn't right, set mChunkSize to zero which signifies that the reader is
// in an invalid state and Read calls will return false;
for (const auto& shm : mData) {
for (const auto& shm : mSmallAllocs) {
if (!shm.IsReadable()
|| shm.Size<uint8_t>() != mChunkSize
|| shm.get<uint8_t>() == nullptr) {
@ -119,16 +149,48 @@ ShmSegmentsReader::ShmSegmentsReader(const nsTArray<ipc::Shmem>& aShmems)
return;
}
}
for (const auto& shm : mLargeAllocs) {
if (!shm.IsReadable()
|| shm.get<uint8_t>() == nullptr) {
mChunkSize = 0;
return;
}
}
}
bool
ShmSegmentsReader::Read(layers::OffsetRange aRange, wr::Vec_u8& aInto)
ShmSegmentsReader::ReadLarge(const layers::OffsetRange& aRange, wr::Vec_u8& aInto)
{
// source = zero is for small allocs.
MOZ_RELEASE_ASSERT(aRange.source() != 0);
if (aRange.source() > mLargeAllocs.Length()) {
return false;
}
size_t id = aRange.source() - 1;
const ipc::Shmem& shm = mLargeAllocs[id];
if (shm.Size<uint8_t>() < aRange.length()) {
return false;
}
uint8_t* srcPtr = shm.get<uint8_t>();
aInto.PushBytes(Range<uint8_t>(srcPtr, aRange.length()));
return true;
}
bool
ShmSegmentsReader::Read(const layers::OffsetRange& aRange, wr::Vec_u8& aInto)
{
if (aRange.source() != 0) {
return ReadLarge(aRange, aInto);
}
if (mChunkSize == 0) {
return false;
}
if (aRange.start() + aRange.length() > mChunkSize * mData.Length()) {
if (aRange.start() + aRange.length() > mChunkSize * mSmallAllocs.Length()) {
return false;
}
@ -140,7 +202,7 @@ ShmSegmentsReader::Read(layers::OffsetRange aRange, wr::Vec_u8& aInto)
const size_t shm_idx = srcCursor / mChunkSize;
const size_t ptrOffset = srcCursor % mChunkSize;
const size_t copyRange = std::min<int>(remainingBytesToCopy, mChunkSize - ptrOffset);
uint8_t* srcPtr = mData[shm_idx].get<uint8_t>() + ptrOffset;
uint8_t* srcPtr = mSmallAllocs[shm_idx].get<uint8_t>() + ptrOffset;
aInto.PushBytes(Range<uint8_t>(srcPtr, copyRange));
@ -172,6 +234,12 @@ IpcResourceUpdateQueue::AddBlobImage(ImageKey key, const ImageDescriptor& aDescr
mUpdates.AppendElement(layers::OpAddBlobImage(aDescriptor, bytes, 0, key));
}
void
IpcResourceUpdateQueue::AddExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey)
{
mUpdates.AppendElement(layers::OpAddExternalImage(aExtId, aKey));
}
void
IpcResourceUpdateQueue::UpdateImageBuffer(ImageKey aKey,
const ImageDescriptor& aDescriptor,
@ -232,11 +300,12 @@ IpcResourceUpdateQueue::DeleteFontInstance(wr::FontInstanceKey aKey)
void
IpcResourceUpdateQueue::Flush(nsTArray<layers::OpUpdateResource>& aUpdates,
nsTArray<ipc::Shmem>& aResourceData)
nsTArray<ipc::Shmem>& aSmallAllocs,
nsTArray<ipc::Shmem>& aLargeAllocs)
{
aUpdates.Clear();
mUpdates.SwapElements(aUpdates);
mWriter.Flush(aResourceData);
mWriter.Flush(aSmallAllocs, aLargeAllocs);
}
void

View File

@ -14,6 +14,8 @@ class IShmemAllocator;
}
namespace wr {
/// ShmSegmentsWriter pushes bytes in a sequence of fixed size shmems for small
/// allocations and creates dedicated shmems for large allocations.
class ShmSegmentsWriter {
public:
ShmSegmentsWriter(ipc::IShmemAllocator* aAllocator, size_t aChunkSize);
@ -21,14 +23,16 @@ public:
layers::OffsetRange Write(Range<uint8_t> aBytes);
void Flush(nsTArray<ipc::Shmem>& aData);
void Flush(nsTArray<ipc::Shmem>& aSmallAllocs, nsTArray<ipc::Shmem>& aLargeAllocs);
void Clear();
protected:
void AllocChunk();
layers::OffsetRange AllocLargeChunk(size_t aSize);
nsTArray<ipc::Shmem> mData;
nsTArray<ipc::Shmem> mSmallAllocs;
nsTArray<ipc::Shmem> mLargeAllocs;
ipc::IShmemAllocator* mShmAllocator;
size_t mCursor;
size_t mChunkSize;
@ -36,24 +40,26 @@ protected:
class ShmSegmentsReader {
public:
explicit ShmSegmentsReader(const nsTArray<ipc::Shmem>& aShmems);
ShmSegmentsReader(const nsTArray<ipc::Shmem>& aSmallShmems,
const nsTArray<ipc::Shmem>& aLargeShmems);
bool Read(layers::OffsetRange aRange, wr::Vec_u8& aInto);
bool Read(const layers::OffsetRange& aRange, wr::Vec_u8& aInto);
protected:
void AllocChunk();
bool ReadLarge(const layers::OffsetRange& aRange, wr::Vec_u8& aInto);
const nsTArray<ipc::Shmem>& mData;
const nsTArray<ipc::Shmem>& mSmallAllocs;
const nsTArray<ipc::Shmem>& mLargeAllocs;
size_t mChunkSize;
};
class IpcResourceUpdateQueue {
public:
// TODO: 8192 is completely arbitrary, needs some adjustments.
// TODO: 32768 is completely arbitrary, needs some adjustments.
// Because we are using shmems, the size should be a multiple of the page size, and keep in mind
// that each shmem has guard pages, one of which contains meta-data so at least an extra page
// is mapped under the hood (so having a lot of smaller shmems = overhead).
explicit IpcResourceUpdateQueue(ipc::IShmemAllocator* aAllocator, size_t aChunkSize = 8192);
explicit IpcResourceUpdateQueue(ipc::IShmemAllocator* aAllocator, size_t aChunkSize = 32768);
void AddImage(wr::ImageKey aKey,
const ImageDescriptor& aDescriptor,
@ -63,6 +69,8 @@ public:
const ImageDescriptor& aDescriptor,
Range<uint8_t> aBytes);
void AddExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey);
void UpdateImageBuffer(wr::ImageKey aKey,
const ImageDescriptor& aDescriptor,
Range<uint8_t> aBytes);
@ -94,7 +102,8 @@ public:
void Clear();
void Flush(nsTArray<layers::OpUpdateResource>& aUpdates,
nsTArray<ipc::Shmem>& aResources);
nsTArray<ipc::Shmem>& aSmallAllocs,
nsTArray<ipc::Shmem>& aLargeAllocs);
protected:
ShmSegmentsWriter mWriter;

View File

@ -17,6 +17,7 @@ namespace layers {
ScrollingLayersHelper::ScrollingLayersHelper(WebRenderLayer* aLayer,
wr::DisplayListBuilder& aBuilder,
wr::IpcResourceUpdateQueue& aResources,
const StackingContextHelper& aStackingContext)
: mLayer(aLayer)
, mBuilder(&aBuilder)
@ -26,7 +27,7 @@ ScrollingLayersHelper::ScrollingLayersHelper(WebRenderLayer* aLayer,
if (!mLayer->WrManager()->AsyncPanZoomEnabled()) {
// If APZ is disabled then we don't need to push the scrolling clips. We
// still want to push the layer's local clip though.
PushLayerLocalClip(aStackingContext);
PushLayerLocalClip(aStackingContext, aResources);
return;
}
@ -39,7 +40,7 @@ ScrollingLayersHelper::ScrollingLayersHelper(WebRenderLayer* aLayer,
// corresponding scroll layer, so that when we set an async scroll position
// on the scroll layer, the clip isn't affected by it.
if (const Maybe<LayerClip>& clip = metadata.GetScrollClip()) {
PushLayerClip(clip.ref(), aStackingContext);
PushLayerClip(clip.ref(), aStackingContext, aResources);
}
const FrameMetrics& fm = layer->GetFrameMetrics(i - 1);
@ -48,7 +49,7 @@ ScrollingLayersHelper::ScrollingLayersHelper(WebRenderLayer* aLayer,
// If the layer contents are fixed for this metadata onwards, we need
// to insert the layer's local clip at this point in the clip tree,
// as a child of whatever's on the stack.
PushLayerLocalClip(aStackingContext);
PushLayerLocalClip(aStackingContext, aResources);
}
DefineAndPushScrollLayer(fm, aStackingContext);
@ -59,7 +60,7 @@ ScrollingLayersHelper::ScrollingLayersHelper(WebRenderLayer* aLayer,
// child layers. So we need to apply this after pushing all the scroll layers,
// which we do above.
if (const Maybe<LayerClip>& scrolledClip = layer->GetScrolledClip()) {
PushLayerClip(scrolledClip.ref(), aStackingContext);
PushLayerClip(scrolledClip.ref(), aStackingContext, aResources);
}
// If the layer is marked as fixed-position, it is fixed relative to something
@ -82,7 +83,7 @@ ScrollingLayersHelper::ScrollingLayersHelper(WebRenderLayer* aLayer,
// Default to 0 if there is no ancestor, because 0 refers to the root scrollframe.
mBuilder->PushClipAndScrollInfo(scrollsWith.valueOr(0), clipId.ptrOr(nullptr));
} else {
PushLayerLocalClip(aStackingContext);
PushLayerLocalClip(aStackingContext, aResources);
}
}
@ -273,7 +274,8 @@ ScrollingLayersHelper::DefineAndPushScrollLayer(const FrameMetrics& aMetrics,
}
void
ScrollingLayersHelper::PushLayerLocalClip(const StackingContextHelper& aStackingContext)
ScrollingLayersHelper::PushLayerLocalClip(const StackingContextHelper& aStackingContext,
wr::IpcResourceUpdateQueue& aResources)
{
Layer* layer = mLayer->GetLayer();
Maybe<ParentLayerRect> clip;
@ -285,7 +287,7 @@ ScrollingLayersHelper::PushLayerLocalClip(const StackingContextHelper& aStacking
clip = Some(layer->GetLocalTransformTyped().TransformBounds(mLayer->Bounds()));
}
if (clip) {
Maybe<wr::WrImageMask> mask = mLayer->BuildWrMaskLayer(aStackingContext);
Maybe<wr::WrImageMask> mask = mLayer->BuildWrMaskLayer(aStackingContext, aResources);
LayerRect clipRect = ViewAs<LayerPixel>(clip.ref(),
PixelCastJustification::MovingDownToChildren);
mBuilder->PushClip(mBuilder->DefineClip(
@ -296,7 +298,8 @@ ScrollingLayersHelper::PushLayerLocalClip(const StackingContextHelper& aStacking
void
ScrollingLayersHelper::PushLayerClip(const LayerClip& aClip,
const StackingContextHelper& aSc)
const StackingContextHelper& aSc,
wr::IpcResourceUpdateQueue& aResources)
{
LayerRect clipRect = IntRectToRect(ViewAs<LayerPixel>(aClip.GetClipRect(),
PixelCastJustification::MovingDownToChildren));
@ -305,7 +308,7 @@ ScrollingLayersHelper::PushLayerClip(const LayerClip& aClip,
Layer* maskLayer = mLayer->GetLayer()->GetAncestorMaskLayerAt(maskLayerIndex.value());
WebRenderLayer* maskWrLayer = WebRenderLayer::ToWebRenderLayer(maskLayer);
// TODO: check this transform is correct in all cases
mask = maskWrLayer->RenderMaskLayer(aSc, maskLayer->GetTransform());
mask = maskWrLayer->RenderMaskLayer(aSc, maskLayer->GetTransform(), aResources);
}
mBuilder->PushClip(mBuilder->DefineClip(
aSc.ToRelativeLayoutRect(clipRect), nullptr, mask.ptrOr(nullptr)));

View File

@ -29,6 +29,7 @@ class MOZ_RAII ScrollingLayersHelper
public:
ScrollingLayersHelper(WebRenderLayer* aLayer,
wr::DisplayListBuilder& aBuilder,
wr::IpcResourceUpdateQueue& aResources,
const StackingContextHelper& aSc);
ScrollingLayersHelper(nsDisplayItem* aItem,
wr::DisplayListBuilder& aBuilder,
@ -52,9 +53,11 @@ private:
WebRenderLayerManager::ClipIdMap& aCache);
bool DefineAndPushScrollLayer(const FrameMetrics& aMetrics,
const StackingContextHelper& aStackingContext);
void PushLayerLocalClip(const StackingContextHelper& aStackingContext);
void PushLayerLocalClip(const StackingContextHelper& aStackingContext,
wr::IpcResourceUpdateQueue& aResources);
void PushLayerClip(const LayerClip& aClip,
const StackingContextHelper& aSc);
const StackingContextHelper& aSc,
wr::IpcResourceUpdateQueue& aResources);
WebRenderLayer* mLayer;
wr::DisplayListBuilder* mBuilder;

View File

@ -107,10 +107,11 @@ WebRenderBridgeChild::UpdateResources(wr::IpcResourceUpdateQueue& aResources)
}
nsTArray<OpUpdateResource> resourceUpdates;
nsTArray<ipc::Shmem> resourceData;
aResources.Flush(resourceUpdates, resourceData);
nsTArray<ipc::Shmem> smallShmems;
nsTArray<ipc::Shmem> largeShmems;
aResources.Flush(resourceUpdates, smallShmems, largeShmems);
this->SendUpdateResources(resourceUpdates, resourceData);
this->SendUpdateResources(resourceUpdates, Move(smallShmems), Move(largeShmems));
}
void
@ -136,20 +137,21 @@ WebRenderBridgeChild::EndTransaction(wr::DisplayListBuilder &aBuilder,
#endif
nsTArray<OpUpdateResource> resourceUpdates;
nsTArray<ipc::Shmem> resourceData;
aResources.Flush(resourceUpdates, resourceData);
nsTArray<ipc::Shmem> smallShmems;
nsTArray<ipc::Shmem> largeShmems;
aResources.Flush(resourceUpdates, smallShmems, largeShmems);
if (aIsSync) {
this->SendSetDisplayListSync(aSize, mParentCommands, mDestroyedActors,
GetFwdTransactionId(), aTransactionId,
contentSize, dlData, dl.dl_desc, aScrollData,
Move(resourceUpdates), Move(resourceData),
Move(resourceUpdates), Move(smallShmems), Move(largeShmems),
mIdNamespace, aTxnStartTime, fwdTime);
} else {
this->SendSetDisplayList(aSize, mParentCommands, mDestroyedActors,
GetFwdTransactionId(), aTransactionId,
contentSize, dlData, dl.dl_desc, aScrollData,
Move(resourceUpdates), Move(resourceData),
Move(resourceUpdates), Move(smallShmems), Move(largeShmems),
mIdNamespace, aTxnStartTime, fwdTime);
}

View File

@ -235,10 +235,11 @@ WebRenderBridgeParent::DeallocShmems(nsTArray<ipc::Shmem>& aShmems)
bool
WebRenderBridgeParent::UpdateResources(const nsTArray<OpUpdateResource>& aResourceUpdates,
const nsTArray<ipc::Shmem>& aResourceData,
const nsTArray<ipc::Shmem>& aSmallShmems,
const nsTArray<ipc::Shmem>& aLargeShmems,
wr::ResourceUpdateQueue& aUpdates)
{
wr::ShmSegmentsReader reader(aResourceData);
wr::ShmSegmentsReader reader(aSmallShmems, aLargeShmems);
for (const auto& cmd : aResourceUpdates) {
switch (cmd.type()) {
@ -278,6 +279,13 @@ WebRenderBridgeParent::UpdateResources(const nsTArray<OpUpdateResource>& aResour
aUpdates.UpdateBlobImage(op.key(), op.descriptor(), bytes);
break;
}
case OpUpdateResource::TOpAddExternalImage: {
const auto& op = cmd.get_OpAddExternalImage();
if (!AddExternalImage(op.externalImageId(), op.key(), aUpdates)) {
return false;
}
break;
}
case OpUpdateResource::TOpAddRawFont: {
const auto& op = cmd.get_OpAddRawFont();
wr::Vec_u8 bytes;
@ -317,24 +325,78 @@ WebRenderBridgeParent::UpdateResources(const nsTArray<OpUpdateResource>& aResour
return true;
}
bool
WebRenderBridgeParent::AddExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey,
wr::ResourceUpdateQueue& aResources)
{
Range<const wr::ImageKey> keys(&aKey, 1);
// Check if key is obsoleted.
if (keys[0].mNamespace != mIdNamespace) {
return true;
}
MOZ_ASSERT(mExternalImageIds.Get(wr::AsUint64(aExtId)).get());
RefPtr<WebRenderImageHost> host = mExternalImageIds.Get(wr::AsUint64(aExtId));
if (!host) {
NS_ERROR("CompositableHost does not exist");
return false;
}
if (!gfxEnv::EnableWebRenderRecording()) {
TextureHost* texture = host->GetAsTextureHostForComposite();
if (!texture) {
NS_ERROR("TextureHost does not exist");
return false;
}
WebRenderTextureHost* wrTexture = texture->AsWebRenderTextureHost();
if (wrTexture) {
wrTexture->AddWRImage(aResources, keys, wrTexture->GetExternalImageKey());
return true;
}
}
RefPtr<DataSourceSurface> dSurf = host->GetAsSurface();
if (!dSurf) {
NS_ERROR("TextureHost does not return DataSourceSurface");
return false;
}
DataSourceSurface::MappedSurface map;
if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
NS_ERROR("DataSourceSurface failed to map");
return false;
}
IntSize size = dSurf->GetSize();
wr::ImageDescriptor descriptor(size, map.mStride, dSurf->GetFormat());
wr::Vec_u8 data;
data.PushBytes(Range<uint8_t>(map.mData, size.height * map.mStride));
aResources.AddImage(keys[0], descriptor, data);
dSurf->Unmap();
return true;
}
mozilla::ipc::IPCResult
WebRenderBridgeParent::RecvUpdateResources(nsTArray<OpUpdateResource>&& aResourceUpdates,
nsTArray<ipc::Shmem>&& aResourceData)
nsTArray<ipc::Shmem>&& aSmallShmems,
nsTArray<ipc::Shmem>&& aLargeShmems)
{
if (mDestroyed) {
DeallocShmems(aResourceData);
DeallocShmems(aSmallShmems);
DeallocShmems(aLargeShmems);
return IPC_OK();
}
wr::ResourceUpdateQueue updates;
if (!UpdateResources(aResourceUpdates, aResourceData, updates)) {
DeallocShmems(aResourceData);
if (!UpdateResources(aResourceUpdates, aSmallShmems, aLargeShmems, updates)) {
DeallocShmems(aSmallShmems);
DeallocShmems(aLargeShmems);
IPC_FAIL(this, "Invalid WebRender resource data shmem or address.");
}
mApi->UpdateResources(updates);
DeallocShmems(aResourceData);
DeallocShmems(aSmallShmems);
DeallocShmems(aLargeShmems);
return IPC_OK();
}
@ -440,7 +502,8 @@ WebRenderBridgeParent::RecvSetDisplayList(const gfx::IntSize& aSize,
const wr::BuiltDisplayListDescriptor& dlDesc,
const WebRenderScrollData& aScrollData,
nsTArray<OpUpdateResource>&& aResourceUpdates,
nsTArray<ipc::Shmem>&& aResourceData,
nsTArray<ipc::Shmem>&& aSmallShmems,
nsTArray<ipc::Shmem>&& aLargeShmems,
const wr::IdNamespace& aIdNamespace,
const TimeStamp& aTxnStartTime,
const TimeStamp& aFwdTime)
@ -449,7 +512,8 @@ WebRenderBridgeParent::RecvSetDisplayList(const gfx::IntSize& aSize,
for (const auto& op : aToDestroy) {
DestroyActor(op);
}
DeallocShmems(aResourceData);
DeallocShmems(aSmallShmems);
DeallocShmems(aLargeShmems);
return IPC_OK();
}
@ -461,12 +525,39 @@ WebRenderBridgeParent::RecvSetDisplayList(const gfx::IntSize& aSize,
// to early-return from RecvDPEnd without doing so.
AutoWebRenderBridgeParentAsyncMessageSender autoAsyncMessageSender(this, &aToDestroy);
wr::ResourceUpdateQueue resources;
UpdateResources(aResourceUpdates, aResourceData, resources);
uint32_t wrEpoch = GetNextWrEpoch();
ProcessWebRenderCommands(aSize, aCommands, wr::NewEpoch(wrEpoch),
aContentSize, dl, dlDesc, resources, aIdNamespace);
wr::ResourceUpdateQueue resources;
mAsyncImageManager->SetCompositionTime(TimeStamp::Now());
ProcessWebRenderParentCommands(aCommands, resources);
if (!UpdateResources(aResourceUpdates, aSmallShmems, aLargeShmems, resources)) {
return IPC_FAIL(this, "Failed to deserialize resource updates");
}
// If id namespaces do not match, it means the command is obsolete, probably
// because the tab just moved to a new window.
// In that case do not send the commands to webrender.
if (mIdNamespace == aIdNamespace) {
if (mWidget) {
LayoutDeviceIntSize size = mWidget->GetClientSize();
mApi->SetWindowParameters(size);
}
gfx::Color color = mWidget ? gfx::Color(0.3f, 0.f, 0.f, 1.f) : gfx::Color(0.f, 0.f, 0.f, 0.f);
mApi->SetDisplayList(color, wr::NewEpoch(wrEpoch), LayerSize(aSize.width, aSize.height),
mPipelineId, aContentSize,
dlDesc, dl.mData, dl.mLength,
resources);
ScheduleComposition();
if (ShouldParentObserveEpoch()) {
mCompositorBridge->ObserveLayerUpdate(GetLayersId(), GetChildLayerObserverEpoch(), true);
}
}
HoldPendingTransactionId(wrEpoch, aTransactionId, aTxnStartTime, aFwdTime);
mScrollData = aScrollData;
@ -479,7 +570,8 @@ WebRenderBridgeParent::RecvSetDisplayList(const gfx::IntSize& aSize,
mCompositorBridge->DidComposite(wr::AsUint64(mPipelineId), now, now);
}
DeallocShmems(aResourceData);
DeallocShmems(aSmallShmems);
DeallocShmems(aLargeShmems);
return IPC_OK();
}
@ -494,7 +586,8 @@ WebRenderBridgeParent::RecvSetDisplayListSync(const gfx::IntSize &aSize,
const wr::BuiltDisplayListDescriptor& dlDesc,
const WebRenderScrollData& aScrollData,
nsTArray<OpUpdateResource>&& aResourceUpdates,
nsTArray<ipc::Shmem>&& aResourceData,
nsTArray<ipc::Shmem>&& aSmallShmems,
nsTArray<ipc::Shmem>&& aLargeShmems,
const wr::IdNamespace& aIdNamespace,
const TimeStamp& aTxnStartTime,
const TimeStamp& aFwdTime)
@ -502,7 +595,7 @@ WebRenderBridgeParent::RecvSetDisplayListSync(const gfx::IntSize &aSize,
return RecvSetDisplayList(aSize, Move(aCommands), Move(aToDestroy),
aFwdTransactionId, aTransactionId,
aContentSize, dl, dlDesc, aScrollData,
Move(aResourceUpdates), Move(aResourceData),
Move(aResourceUpdates), Move(aSmallShmems), Move(aLargeShmems),
aIdNamespace, aTxnStartTime, aFwdTime);
}
@ -525,53 +618,6 @@ WebRenderBridgeParent::ProcessWebRenderParentCommands(const InfallibleTArray<Web
for (InfallibleTArray<WebRenderParentCommand>::index_type i = 0; i < aCommands.Length(); ++i) {
const WebRenderParentCommand& cmd = aCommands[i];
switch (cmd.type()) {
case WebRenderParentCommand::TOpAddExternalImage: {
const OpAddExternalImage& op = cmd.get_OpAddExternalImage();
Range<const wr::ImageKey> keys(&op.key(), 1);
// Check if key is obsoleted.
if (keys[0].mNamespace != mIdNamespace) {
break;
}
MOZ_ASSERT(mExternalImageIds.Get(wr::AsUint64(op.externalImageId())).get());
RefPtr<WebRenderImageHost> host = mExternalImageIds.Get(wr::AsUint64(op.externalImageId()));
if (!host) {
NS_ERROR("CompositableHost does not exist");
break;
}
if (!gfxEnv::EnableWebRenderRecording()) {
TextureHost* texture = host->GetAsTextureHostForComposite();
if (!texture) {
NS_ERROR("TextureHost does not exist");
break;
}
WebRenderTextureHost* wrTexture = texture->AsWebRenderTextureHost();
if (wrTexture) {
wrTexture->AddWRImage(aResources, keys, wrTexture->GetExternalImageKey());
break;
}
}
RefPtr<DataSourceSurface> dSurf = host->GetAsSurface();
if (!dSurf) {
NS_ERROR("TextureHost does not return DataSourceSurface");
break;
}
DataSourceSurface::MappedSurface map;
if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
NS_ERROR("DataSourceSurface failed to map");
break;
}
IntSize size = dSurf->GetSize();
wr::ImageDescriptor descriptor(size, map.mStride, dSurf->GetFormat());
wr::Vec_u8 data;
data.PushBytes(Range<uint8_t>(map.mData, size.height * map.mStride));
aResources.AddImage(keys[0], descriptor, data);
dSurf->Unmap();
break;
}
case WebRenderParentCommand::TOpUpdateAsyncImagePipeline: {
const OpUpdateAsyncImagePipeline& op = cmd.get_OpUpdateAsyncImagePipeline();
mAsyncImageManager->UpdateAsyncImagePipeline(op.pipelineId(),
@ -614,40 +660,6 @@ WebRenderBridgeParent::ProcessWebRenderParentCommands(const InfallibleTArray<Web
}
}
void
WebRenderBridgeParent::ProcessWebRenderCommands(const gfx::IntSize &aSize,
InfallibleTArray<WebRenderParentCommand>& aCommands, const wr::Epoch& aEpoch,
const wr::LayoutSize& aContentSize, const wr::ByteBuffer& dl,
const wr::BuiltDisplayListDescriptor& dlDesc,
wr::ResourceUpdateQueue& aResourceUpdates,
const wr::IdNamespace& aIdNamespace)
{
mAsyncImageManager->SetCompositionTime(TimeStamp::Now());
ProcessWebRenderParentCommands(aCommands, aResourceUpdates);
// The command is obsoleted.
// Do not set the command to webrender since it causes crash in webrender.
if (mIdNamespace != aIdNamespace) {
return;
}
if (mWidget) {
LayoutDeviceIntSize size = mWidget->GetClientSize();
mApi->SetWindowParameters(size);
}
gfx::Color color = mWidget ? gfx::Color(0.3f, 0.f, 0.f, 1.f) : gfx::Color(0.f, 0.f, 0.f, 0.f);
mApi->SetDisplayList(color, aEpoch, LayerSize(aSize.width, aSize.height),
mPipelineId, aContentSize,
dlDesc, dl.mData, dl.mLength,
aResourceUpdates);
ScheduleComposition();
if (ShouldParentObserveEpoch()) {
mCompositorBridge->ObserveLayerUpdate(GetLayersId(), GetChildLayerObserverEpoch(), true);
}
}
mozilla::ipc::IPCResult
WebRenderBridgeParent::RecvGetSnapshot(PTextureParent* aTexture)
{

View File

@ -74,7 +74,8 @@ public:
mozilla::ipc::IPCResult RecvShutdownSync() override;
mozilla::ipc::IPCResult RecvDeleteCompositorAnimations(InfallibleTArray<uint64_t>&& aIds) override;
mozilla::ipc::IPCResult RecvUpdateResources(nsTArray<OpUpdateResource>&& aUpdates,
nsTArray<ipc::Shmem>&& aResourceData) override;
nsTArray<ipc::Shmem>&& aSmallShmems,
nsTArray<ipc::Shmem>&& aLargeShmems) override;
mozilla::ipc::IPCResult RecvSetDisplayList(const gfx::IntSize& aSize,
InfallibleTArray<WebRenderParentCommand>&& aCommands,
InfallibleTArray<OpDestroy>&& aToDestroy,
@ -85,7 +86,8 @@ public:
const wr::BuiltDisplayListDescriptor& dlDesc,
const WebRenderScrollData& aScrollData,
nsTArray<OpUpdateResource>&& aResourceUpdates,
nsTArray<ipc::Shmem>&& aResourceData,
nsTArray<ipc::Shmem>&& aSmallShmems,
nsTArray<ipc::Shmem>&& aLargeShmems,
const wr::IdNamespace& aIdNamespace,
const TimeStamp& aTxnStartTime,
const TimeStamp& aFwdTime) override;
@ -99,7 +101,8 @@ public:
const wr::BuiltDisplayListDescriptor& dlDesc,
const WebRenderScrollData& aScrollData,
nsTArray<OpUpdateResource>&& aResourceUpdates,
nsTArray<ipc::Shmem>&& aResourceData,
nsTArray<ipc::Shmem>&& aSmallShmems,
nsTArray<ipc::Shmem>&& aLargeShmems,
const wr::IdNamespace& aIdNamespace,
const TimeStamp& aTxnStartTime,
const TimeStamp& aFwdTime) override;
@ -190,20 +193,16 @@ private:
virtual ~WebRenderBridgeParent();
bool UpdateResources(const nsTArray<OpUpdateResource>& aResourceUpdates,
const nsTArray<ipc::Shmem>& aResourceData,
const nsTArray<ipc::Shmem>& aSmallShmems,
const nsTArray<ipc::Shmem>& aLargeShmems,
wr::ResourceUpdateQueue& aUpdates);
bool AddExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey,
wr::ResourceUpdateQueue& aResources);
uint64_t GetLayersId() const;
void ProcessWebRenderParentCommands(const InfallibleTArray<WebRenderParentCommand>& aCommands,
wr::ResourceUpdateQueue& aResources);
void ProcessWebRenderCommands(const gfx::IntSize &aSize,
InfallibleTArray<WebRenderParentCommand>& commands,
const wr::Epoch& aEpoch,
const wr::LayoutSize& aContentSize,
const wr::ByteBuffer& dl,
const wr::BuiltDisplayListDescriptor& dlDesc,
wr::ResourceUpdateQueue& aResourceUpdates,
const wr::IdNamespace& aIdNamespace);
void ClearResources();
uint64_t GetChildLayerObserverEpoch() const { return mChildLayerObserverEpoch; }
bool ShouldParentObserveEpoch();

View File

@ -16,6 +16,7 @@
#include "mozilla/layers/StackingContextHelper.h"
#include "mozilla/layers/TextureClientSharedSurface.h"
#include "mozilla/layers/WebRenderBridgeChild.h"
#include "mozilla/layers/IpcResourceUpdateQueue.h"
#include "PersistentBufferProvider.h"
#include "SharedSurface.h"
#include "SharedSurfaceGL.h"
@ -50,7 +51,7 @@ WebRenderCanvasLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
transform = Some(GetTransform().PreTranslate(0, mBounds.Height(), 0).PreScale(1, -1, 1));
}
ScrollingLayersHelper scroller(this, aBuilder, aSc);
ScrollingLayersHelper scroller(this, aBuilder, aResources, aSc);
StackingContextHelper sc(aSc, aBuilder, this, transform);
LayerRect rect(0, 0, mBounds.Width(), mBounds.Height());
@ -64,8 +65,11 @@ WebRenderCanvasLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
Stringify(filter).c_str());
}
// Eww. Re-creating image keys every time is bad. Probably not worth fixing here
// since layers-full webrender is going away soon-ish. But don't reproduce what
// you see here.
wr::WrImageKey key = GenerateImageKey();
WrBridge()->AddWebRenderParentCommand(OpAddExternalImage(canvasRenderer->GetExternalImageId().value(), key));
aResources.AddExternalImage(canvasRenderer->GetExternalImageId().value(), key);
WrManager()->AddImageKeyForDiscard(key);
wr::LayoutRect r = sc.ToRelativeLayoutRect(rect);

View File

@ -33,7 +33,7 @@ public:
protected:
virtual ~WebRenderCanvasLayer();
Maybe<wr::ImageKey> mKey;
public:
Layer* GetLayer() override { return this; }
void RenderLayer(wr::DisplayListBuilder& aBuilder,

View File

@ -23,7 +23,7 @@ WebRenderColorLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
wr::IpcResourceUpdateQueue& aResources,
const StackingContextHelper& aSc)
{
ScrollingLayersHelper scroller(this, aBuilder, aSc);
ScrollingLayersHelper scroller(this, aBuilder, aResources, aSc);
StackingContextHelper sc(aSc, aBuilder, this);
LayerRect rect = Bounds();

View File

@ -107,7 +107,7 @@ WebRenderContainerLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
filters.AppendElement(wr::ToWrFilterOp(filter));
}
ScrollingLayersHelper scroller(this, aBuilder, aSc);
ScrollingLayersHelper scroller(this, aBuilder, aResources, aSc);
StackingContextHelper sc(aSc, aBuilder, this, animationsId, opacityForSC, transformForSC, filters);
LayerRect rect = Bounds();
@ -126,7 +126,7 @@ WebRenderRefLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
wr::IpcResourceUpdateQueue& aResources,
const StackingContextHelper& aSc)
{
ScrollingLayersHelper scroller(this, aBuilder, aSc);
ScrollingLayersHelper scroller(this, aBuilder, aResources, aSc);
ParentLayerRect bounds = GetLocalTransformTyped().TransformBounds(Bounds());
// As with WebRenderTextLayer, because we don't push a stacking context for

View File

@ -32,15 +32,14 @@ WebRenderDisplayItemLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
return;
}
ScrollingLayersHelper scroller(this, aBuilder, aSc);
ScrollingLayersHelper scroller(this, aBuilder, aResources, aSc);
if (mItem) {
wr::LayoutSize contentSize; // this won't actually be used by anything
wr::DisplayListBuilder builder(WrBridge()->GetPipeline(), contentSize);
// We might have recycled this layer. Throw away the old commands.
mParentCommands.Clear();
mItem->CreateWebRenderCommands(builder, aResources, aSc, mParentCommands, WrManager(),
mItem->CreateWebRenderCommands(builder, aResources, aSc, WrManager(),
GetDisplayListBuilder());
builder.Finalize(contentSize, mBuiltDisplayList);
} else {
@ -58,7 +57,6 @@ WebRenderDisplayItemLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
}
aBuilder.PushBuiltDisplayList(mBuiltDisplayList);
WrBridge()->AddWebRenderParentCommands(mParentCommands);
}
} // namespace layers

View File

@ -37,7 +37,6 @@ public:
private:
wr::BuiltDisplayList mBuiltDisplayList;
nsTArray<WebRenderParentCommand> mParentCommands;
};
} // namespace layers

View File

@ -10,6 +10,7 @@
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/layers/CompositorBridgeChild.h"
#include "mozilla/layers/ImageClient.h"
#include "mozilla/layers/IpcResourceUpdateQueue.h"
#include "mozilla/layers/ScrollingLayersHelper.h"
#include "mozilla/layers/StackingContextHelper.h"
#include "mozilla/layers/TextureClientRecycleAllocator.h"
@ -24,6 +25,7 @@ using namespace gfx;
WebRenderImageLayer::WebRenderImageLayer(WebRenderLayerManager* aLayerManager)
: ImageLayer(aLayerManager, static_cast<WebRenderLayer*>(this))
, mKey(Nothing())
, mImageClientContainerType(CompositableType::UNKNOWN)
{
MOZ_COUNT_CTOR(WebRenderImageLayer);
@ -108,6 +110,43 @@ WebRenderImageLayer::SupportsAsyncUpdate()
return false;
}
Maybe<wr::ImageKey>
WebRenderImageLayer::UpdateImageKey(ImageClientSingle* aImageClient,
ImageContainer* aContainer,
Maybe<wr::ImageKey>& aOldKey,
wr::ExternalImageId& aExternalImageId,
wr::IpcResourceUpdateQueue& aResources)
{
MOZ_ASSERT(aImageClient);
MOZ_ASSERT(aContainer);
uint32_t oldCounter = aImageClient->GetLastUpdateGenerationCounter();
bool ret = aImageClient->UpdateImage(aContainer, /* unused */0);
if (!ret || aImageClient->IsEmpty()) {
// Delete old key
if (aOldKey.isSome()) {
WrManager()->AddImageKeyForDiscard(aOldKey.value());
}
return Nothing();
}
// Reuse old key if generation is not updated.
if (oldCounter == aImageClient->GetLastUpdateGenerationCounter() && aOldKey.isSome()) {
return aOldKey;
}
// Delete old key, we are generating a new key.
// TODO: stop doing this!
if (aOldKey.isSome()) {
WrManager()->AddImageKeyForDiscard(aOldKey.value());
}
wr::WrImageKey key = GenerateImageKey();
aResources.AddExternalImage(aExternalImageId, key);
return Some(key);
}
void
WebRenderImageLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
wr::IpcResourceUpdateQueue& aResources,
@ -153,7 +192,7 @@ WebRenderImageLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
// Push IFrame for async image pipeline.
// XXX Remove this once partial display list update is supported.
ScrollingLayersHelper scroller(this, aBuilder, aSc);
ScrollingLayersHelper scroller(this, aBuilder, aResources, aSc);
ParentLayerRect bounds = GetLocalTransformTyped().TransformBounds(Bounds());
@ -209,12 +248,13 @@ WebRenderImageLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
mKey = UpdateImageKey(mImageClient->AsImageClientSingle(),
mContainer,
mKey,
mExternalImageId.ref());
mExternalImageId.ref(),
aResources);
if (mKey.isNothing()) {
return;
}
ScrollingLayersHelper scroller(this, aBuilder, aSc);
ScrollingLayersHelper scroller(this, aBuilder, aResources, aSc);
StackingContextHelper sc(aSc, aBuilder, this);
LayerRect rect(0, 0, size.width, size.height);
@ -238,7 +278,8 @@ WebRenderImageLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
Maybe<wr::WrImageMask>
WebRenderImageLayer::RenderMaskLayer(const StackingContextHelper& aSc,
const gfx::Matrix4x4& aTransform)
const gfx::Matrix4x4& aTransform,
wr::IpcResourceUpdateQueue& aResources)
{
if (!mContainer) {
return Nothing();
@ -278,7 +319,8 @@ WebRenderImageLayer::RenderMaskLayer(const StackingContextHelper& aSc,
mKey = UpdateImageKey(mImageClient->AsImageClientSingle(),
mContainer,
mKey,
mExternalImageId.ref());
mExternalImageId.ref(),
aResources);
if (mKey.isNothing()) {
return Nothing();
}

View File

@ -35,7 +35,8 @@ public:
wr::IpcResourceUpdateQueue& aResources,
const StackingContextHelper& aSc) override;
Maybe<wr::WrImageMask> RenderMaskLayer(const StackingContextHelper& aSc,
const gfx::Matrix4x4& aTransform) override;
const gfx::Matrix4x4& aTransform,
wr::IpcResourceUpdateQueue& aResources) override;
protected:
CompositableType GetImageClientType();
@ -43,6 +44,13 @@ protected:
void AddWRVideoImage(size_t aChannelNumber);
Maybe<wr::ImageKey>
UpdateImageKey(ImageClientSingle* aImageClient,
ImageContainer* aContainer,
Maybe<wr::ImageKey>& aOldKey,
wr::ExternalImageId& aExternalImageId,
wr::IpcResourceUpdateQueue& aResources);
wr::MaybeExternalImageId mExternalImageId;
Maybe<wr::ImageKey> mKey;
RefPtr<ImageClient> mImageClient;

View File

@ -41,12 +41,13 @@ WebRenderLayer::GenerateImageKey()
}
Maybe<wr::WrImageMask>
WebRenderLayer::BuildWrMaskLayer(const StackingContextHelper& aRelativeTo)
WebRenderLayer::BuildWrMaskLayer(const StackingContextHelper& aRelativeTo,
wr::IpcResourceUpdateQueue& aResources)
{
if (GetLayer()->GetMaskLayer()) {
WebRenderLayer* maskLayer = ToWebRenderLayer(GetLayer()->GetMaskLayer());
gfx::Matrix4x4 transform = maskLayer->GetLayer()->GetTransform();
return maskLayer->RenderMaskLayer(aRelativeTo, transform);
return maskLayer->RenderMaskLayer(aRelativeTo, transform, aResources);
}
return Nothing();
@ -81,41 +82,6 @@ WebRenderLayer::BoundsForStackingContext()
return bounds;
}
Maybe<wr::ImageKey>
WebRenderLayer::UpdateImageKey(ImageClientSingle* aImageClient,
ImageContainer* aContainer,
Maybe<wr::ImageKey>& aOldKey,
wr::ExternalImageId& aExternalImageId)
{
MOZ_ASSERT(aImageClient);
MOZ_ASSERT(aContainer);
uint32_t oldCounter = aImageClient->GetLastUpdateGenerationCounter();
bool ret = aImageClient->UpdateImage(aContainer, /* unused */0);
if (!ret || aImageClient->IsEmpty()) {
// Delete old key
if (aOldKey.isSome()) {
WrManager()->AddImageKeyForDiscard(aOldKey.value());
}
return Nothing();
}
// Reuse old key if generation is not updated.
if (oldCounter == aImageClient->GetLastUpdateGenerationCounter() && aOldKey.isSome()) {
return aOldKey;
}
// Delete old key, we are generating a new key.
if (aOldKey.isSome()) {
WrManager()->AddImageKeyForDiscard(aOldKey.value());
}
wr::WrImageKey key = GenerateImageKey();
WrBridge()->AddWebRenderParentCommand(OpAddExternalImage(aExternalImageId, key));
return Some(key);
}
void
WebRenderLayer::DumpLayerInfo(const char* aLayerType, const LayerRect& aRect)
{

View File

@ -11,6 +11,9 @@
#include "mozilla/webrender/WebRenderAPI.h"
namespace mozilla {
namespace wr {
class IpcResourceUpdateQueue;
}
namespace layers {
class ImageClientSingle;
@ -28,7 +31,8 @@ public:
wr::IpcResourceUpdateQueue& aResources,
const StackingContextHelper& aSc) = 0;
virtual Maybe<wr::WrImageMask> RenderMaskLayer(const StackingContextHelper& aSc,
const gfx::Matrix4x4& aTransform)
const gfx::Matrix4x4& aTransform,
wr::IpcResourceUpdateQueue& aResources)
{
MOZ_ASSERT(false);
return Nothing();
@ -41,11 +45,6 @@ public:
return static_cast<WebRenderLayer*>(aLayer->ImplData());
}
Maybe<wr::ImageKey> UpdateImageKey(ImageClientSingle* aImageClient,
ImageContainer* aContainer,
Maybe<wr::ImageKey>& aOldKey,
wr::ExternalImageId& aExternalImageId);
WebRenderLayerManager* WrManager();
WebRenderBridgeChild* WrBridge();
wr::WrImageKey GenerateImageKey();
@ -58,7 +57,8 @@ public:
// that we want this mask to be relative to. This is usually the stacking
// context of the *parent* layer of |this|, because that is what the mask
// is relative to in the layer tree.
Maybe<wr::WrImageMask> BuildWrMaskLayer(const StackingContextHelper& aRelativeTo);
Maybe<wr::WrImageMask> BuildWrMaskLayer(const StackingContextHelper& aRelativeTo,
wr::IpcResourceUpdateQueue& aResources);
protected:
BoundsTransformMatrix BoundsTransform();

View File

@ -341,7 +341,7 @@ WebRenderLayerManager::CreateWebRenderCommandsFromDisplayList(nsDisplayList* aDi
// Note: this call to CreateWebRenderCommands can recurse back into
// this function if the |item| is a wrapper for a sublist.
if (!item->CreateWebRenderCommands(aBuilder, aResources, aSc, mParentCommands, this,
if (!item->CreateWebRenderCommands(aBuilder, aResources, aSc, this,
aDisplayListBuilder)) {
PushItemAsImage(item, aBuilder, aResources, aSc, aDisplayListBuilder);
}
@ -391,6 +391,7 @@ Maybe<wr::ImageKey>
WebRenderLayerManager::CreateImageKey(nsDisplayItem* aItem,
ImageContainer* aContainer,
mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const StackingContextHelper& aSc,
gfx::IntSize& aSize)
{
@ -409,6 +410,9 @@ WebRenderLayerManager::CreateImageKey(nsDisplayItem* aItem,
if (!aContainer->GetScaleHint().IsEmpty()) {
scaleToSize = Some(aContainer->GetScaleHint());
}
// TODO!
// We appear to be using the image bridge for a lot (most/all?) of
// layers-free image handling and that breaks frame consistency.
imageData->CreateAsyncImageWebRenderCommands(aBuilder,
aContainer,
aSc,
@ -428,18 +432,21 @@ WebRenderLayerManager::CreateImageKey(nsDisplayItem* aItem,
mozilla::layers::Image* image = autoLock.GetImage();
aSize = image->GetSize();
return imageData->UpdateImageKey(aContainer);
return imageData->UpdateImageKey(aContainer, aResources);
}
bool
WebRenderLayerManager::PushImage(nsDisplayItem* aItem,
ImageContainer* aContainer,
mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const StackingContextHelper& aSc,
const LayerRect& aRect)
{
gfx::IntSize size;
Maybe<wr::ImageKey> key = CreateImageKey(aItem, aContainer, aBuilder, aSc, size);
Maybe<wr::ImageKey> key = CreateImageKey(aItem, aContainer,
aBuilder, aResources,
aSc, size);
if (aContainer->IsAsync()) {
// Async ImageContainer does not create ImageKey, instead it uses Pipeline.
MOZ_ASSERT(key.isNothing());
@ -615,7 +622,7 @@ WebRenderLayerManager::GenerateFallbackData(nsDisplayItem* aItem,
// Force update the key in fallback data since we repaint the image in this path.
// If not force update, fallbackData may reuse the original key because it
// doesn't know UpdateImageHelper already updated the image container.
if (!fallbackData->UpdateImageKey(imageContainer, true)) {
if (!fallbackData->UpdateImageKey(imageContainer, aResources, true)) {
return nullptr;
}
}

View File

@ -65,11 +65,13 @@ public:
Maybe<wr::ImageKey> CreateImageKey(nsDisplayItem* aItem,
ImageContainer* aContainer,
mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const StackingContextHelper& aSc,
gfx::IntSize& aSize);
bool PushImage(nsDisplayItem* aItem,
ImageContainer* aContainer,
mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const StackingContextHelper& aSc,
const LayerRect& aRect);

View File

@ -8,6 +8,7 @@
#include "LayersLogging.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/layers/ImageClient.h"
#include "mozilla/layers/IpcResourceUpdateQueue.h"
#include "mozilla/layers/ScrollingLayersHelper.h"
#include "mozilla/layers/StackingContextHelper.h"
#include "mozilla/layers/WebRenderBridgeChild.h"
@ -91,16 +92,18 @@ WebRenderPaintedLayer::UpdateImageClient()
void
WebRenderPaintedLayer::CreateWebRenderDisplayList(wr::DisplayListBuilder& aBuilder,
wr::IpcResourceUpdateQueue& aResources,
const StackingContextHelper& aSc)
{
ScrollingLayersHelper scroller(this, aBuilder, aSc);
ScrollingLayersHelper scroller(this, aBuilder, aResources, aSc);
StackingContextHelper sc(aSc, aBuilder, this);
LayerRect rect = Bounds();
DumpLayerInfo("PaintedLayer", rect);
wr::WrImageKey key = GenerateImageKey();
WrBridge()->AddWebRenderParentCommand(OpAddExternalImage(mExternalImageId.value(), key));
aResources.AddExternalImage(mExternalImageId.value(), key);
// TODO: reuse image keys!
WrManager()->AddImageKeyForDiscard(key);
wr::LayoutRect r = sc.ToRelativeLayoutRect(rect);
@ -161,7 +164,7 @@ WebRenderPaintedLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
MOZ_ASSERT(mImageContainer->HasCurrentImage());
}
CreateWebRenderDisplayList(aBuilder, aSc);
CreateWebRenderDisplayList(aBuilder, aResources, aSc);
}
void

View File

@ -57,6 +57,7 @@ private:
bool SetupExternalImages();
bool UpdateImageClient();
void CreateWebRenderDisplayList(wr::DisplayListBuilder& aBuilder,
wr::IpcResourceUpdateQueue& aResources,
const StackingContextHelper& aSc);
void ClearWrResources();
};

View File

@ -86,7 +86,7 @@ WebRenderPaintedLayerBlob::RenderLayer(wr::DisplayListBuilder& aBuilder,
mImageBounds = visibleRegion.GetBounds();
}
ScrollingLayersHelper scroller(this, aBuilder, aSc);
ScrollingLayersHelper scroller(this, aBuilder, aResources, aSc);
StackingContextHelper sc(aSc, aBuilder, this);
LayerRect rect = Bounds();
DumpLayerInfo("PaintedLayer", rect);

View File

@ -27,7 +27,7 @@ WebRenderTextLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
return;
}
ScrollingLayersHelper scroller(this, aBuilder, aSc);
ScrollingLayersHelper scroller(this, aBuilder, aResources, aSc);
LayerRect rect = LayerRect::FromUnknownRect(
// I am not 100% sure this is correct, but it probably is. Because:

View File

@ -9,6 +9,7 @@
#include "mozilla/layers/WebRenderBridgeChild.h"
#include "mozilla/layers/WebRenderLayerManager.h"
#include "mozilla/layers/WebRenderMessages.h"
#include "mozilla/layers/IpcResourceUpdateQueue.h"
#include "nsDisplayListInvalidation.h"
#include "WebRenderCanvasRenderer.h"
@ -69,7 +70,9 @@ WebRenderImageData::~WebRenderImageData()
}
Maybe<wr::ImageKey>
WebRenderImageData::UpdateImageKey(ImageContainer* aContainer, bool aForceUpdate)
WebRenderImageData::UpdateImageKey(ImageContainer* aContainer,
wr::IpcResourceUpdateQueue& aResources,
bool aForceUpdate)
{
CreateImageClientIfNeeded();
CreateExternalImageIfNeeded();
@ -104,12 +107,13 @@ WebRenderImageData::UpdateImageKey(ImageContainer* aContainer, bool aForceUpdate
}
// Delete old key, we are generating a new key.
// TODO(nical): noooo... we need to reuse image keys.
if (mKey) {
mWRManager->AddImageKeyForDiscard(mKey.value());
}
wr::WrImageKey key = WrBridge()->GetNextImageKey();
mWRManager->WrBridge()->AddWebRenderParentCommand(OpAddExternalImage(mExternalImageId.value(), key));
aResources.AddExternalImage(mExternalImageId.value(), key);
mKey = Some(key);
return mKey;

View File

@ -13,6 +13,10 @@
class nsDisplayItemGeometry;
namespace mozilla {
namespace wr {
class IpcResourceUpdateQueue;
}
namespace layers {
class CanvasLayer;
class ImageClient;
@ -79,7 +83,9 @@ public:
void SetKey(const wr::ImageKey& aKey) { mKey = Some(aKey); }
already_AddRefed<ImageClient> GetImageClient();
Maybe<wr::ImageKey> UpdateImageKey(ImageContainer* aContainer, bool aForceUpdate = false);
Maybe<wr::ImageKey> UpdateImageKey(ImageContainer* aContainer,
wr::IpcResourceUpdateQueue& aResources,
bool aForceUpdate = false);
void CreateAsyncImageWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
ImageContainer* aContainer,

View File

@ -699,11 +699,17 @@ gfxDWriteFontEntry::IsCJKFont()
mIsCJK = false;
const uint32_t kOS2Tag = TRUETYPE_TAG('O','S','/','2');
AutoTArray<uint8_t, 128> buffer;
if (CopyFontTable(kOS2Tag, buffer) != NS_OK) {
hb_blob_t* blob = GetFontTable(kOS2Tag);
if (!blob) {
return mIsCJK;
}
// |blob| is an owning reference, but is not RAII-managed, so it must be
// explicitly freed using |hb_blob_destroy| before we return. (Beware of
// adding any early-return codepaths!)
uint32_t len;
const OS2Table* os2 =
reinterpret_cast<const OS2Table*>(hb_blob_get_data(blob, &len));
// ulCodePageRange bit definitions for the CJK codepages,
// from http://www.microsoft.com/typography/otspec/os2.htm#cpr
const uint32_t CJK_CODEPAGE_BITS =
@ -712,14 +718,12 @@ gfxDWriteFontEntry::IsCJKFont()
(1 << 19) | // codepage 949 - Korean Wansung
(1 << 20) | // codepage 950 - Chinese (traditional)
(1 << 21); // codepage 1361 - Korean Johab
if (buffer.Length() >= offsetof(OS2Table, sxHeight)) {
const OS2Table* os2 =
reinterpret_cast<const OS2Table*>(buffer.Elements());
if (len >= offsetof(OS2Table, sxHeight)) {
if ((uint32_t(os2->codePageRange1) & CJK_CODEPAGE_BITS) != 0) {
mIsCJK = true;
}
}
hb_blob_destroy(blob);
return mIsCJK;
}

View File

@ -25,6 +25,29 @@
#include "nsThreadUtils.h"
#include "nsXULAppAPI.h"
#if defined(MOZ_CRASHREPORTER)
#include "nsExceptionHandler.h"
#include "nsPrintfCString.h"
#define ENSURE_HR_SUCCEEDED(hr) \
if (FAILED(hr)) { \
nsPrintfCString location("ENSURE_HR_SUCCEEDED \"%s\": %u", __FILE__, __LINE__); \
nsPrintfCString hrAsStr("0x%08X", hr); \
CrashReporter::AnnotateCrashReport(location, hrAsStr); \
MOZ_DIAGNOSTIC_ASSERT(SUCCEEDED(hr)); \
return hr; \
}
#else
#define ENSURE_HR_SUCCEEDED(hr) \
if (FAILED(hr)) { \
return hr; \
}
#endif // defined(MOZ_CRASHREPORTER)
namespace mozilla {
namespace mscom {
namespace detail {
@ -412,11 +435,11 @@ Interceptor::GetInitialInterceptorForIID(detail::LiveSetAutoLock& aLiveSetLock,
AutoLock lock(*this);
HRESULT hr = PublishTarget(aLiveSetLock, nullptr, aTargetIid, Move(aTarget));
if (FAILED(hr)) {
return hr;
}
ENSURE_HR_SUCCEEDED(hr);
return QueryInterface(aTargetIid, aOutInterceptor);
hr = QueryInterface(aTargetIid, aOutInterceptor);
ENSURE_HR_SUCCEEDED(hr);
return hr;
}
// Raise the refcount for stabilization purposes during aggregation
@ -426,36 +449,32 @@ Interceptor::GetInitialInterceptorForIID(detail::LiveSetAutoLock& aLiveSetLock,
RefPtr<IUnknown> unkInterceptor;
HRESULT hr = CreateInterceptor(aTargetIid, kungFuDeathGrip,
getter_AddRefs(unkInterceptor));
if (FAILED(hr)) {
return hr;
}
ENSURE_HR_SUCCEEDED(hr);
RefPtr<ICallInterceptor> interceptor;
hr = unkInterceptor->QueryInterface(IID_ICallInterceptor,
getter_AddRefs(interceptor));
if (FAILED(hr)) {
return hr;
}
ENSURE_HR_SUCCEEDED(hr);
hr = interceptor->RegisterSink(mEventSink);
if (FAILED(hr)) {
return hr;
}
ENSURE_HR_SUCCEEDED(hr);
// We must lock ourselves so that nothing can race with us once we have been
// published to the live set.
AutoLock lock(*this);
hr = PublishTarget(aLiveSetLock, unkInterceptor, aTargetIid, Move(aTarget));
if (FAILED(hr)) {
ENSURE_HR_SUCCEEDED(hr);
if (mEventSink->MarshalAs(aTargetIid) == aTargetIid) {
hr = unkInterceptor->QueryInterface(aTargetIid, aOutInterceptor);
ENSURE_HR_SUCCEEDED(hr);
return hr;
}
if (mEventSink->MarshalAs(aTargetIid) == aTargetIid) {
return unkInterceptor->QueryInterface(aTargetIid, aOutInterceptor);
}
return GetInterceptorForIID(aTargetIid, aOutInterceptor);
hr = GetInterceptorForIID(aTargetIid, aOutInterceptor);
ENSURE_HR_SUCCEEDED(hr);
return hr;
}
/**
@ -505,7 +524,9 @@ Interceptor::GetInterceptorForIID(REFIID aIid, void** aOutInterceptor)
// was requested.
InterceptorLog::QI(S_OK, mTarget.get(), aIid, interfaceForQILog);
return unkInterceptor->QueryInterface(interceptorIid, aOutInterceptor);
HRESULT hr = unkInterceptor->QueryInterface(interceptorIid, aOutInterceptor);
ENSURE_HR_SUCCEEDED(hr);
return hr;
}
// (2) Obtain a new target interface.
@ -522,9 +543,10 @@ Interceptor::GetInterceptorForIID(REFIID aIid, void** aOutInterceptor)
targetInterface.reset(rawTargetInterface);
InterceptorLog::QI(hr, mTarget.get(), aIid, targetInterface.get());
MOZ_ASSERT(SUCCEEDED(hr) || hr == E_NOINTERFACE);
if (FAILED(hr)) {
if (hr == E_NOINTERFACE) {
return hr;
}
ENSURE_HR_SUCCEEDED(hr);
// We *really* shouldn't be adding interceptors to proxies
MOZ_ASSERT(aIid != IID_IMarshal);
@ -538,23 +560,17 @@ Interceptor::GetInterceptorForIID(REFIID aIid, void** aOutInterceptor)
hr = CreateInterceptor(interceptorIid, kungFuDeathGrip,
getter_AddRefs(unkInterceptor));
if (FAILED(hr)) {
return hr;
}
ENSURE_HR_SUCCEEDED(hr);
// (4) Obtain the interceptor's ICallInterceptor interface and register our
// event sink.
RefPtr<ICallInterceptor> interceptor;
hr = unkInterceptor->QueryInterface(IID_ICallInterceptor,
(void**)getter_AddRefs(interceptor));
if (FAILED(hr)) {
return hr;
}
ENSURE_HR_SUCCEEDED(hr);
hr = interceptor->RegisterSink(mEventSink);
if (FAILED(hr)) {
return hr;
}
ENSURE_HR_SUCCEEDED(hr);
// (5) Now that we have this new COM interceptor, insert it into the map.
@ -576,7 +592,9 @@ Interceptor::GetInterceptorForIID(REFIID aIid, void** aOutInterceptor)
}
}
return unkInterceptor->QueryInterface(interceptorIid, aOutInterceptor);
hr = unkInterceptor->QueryInterface(interceptorIid, aOutInterceptor);
ENSURE_HR_SUCCEEDED(hr);
return hr;
}
HRESULT
@ -638,16 +656,12 @@ Interceptor::ThreadSafeQueryInterface(REFIID aIid, IUnknown** aOutInterface)
SMEXF_SERVER, getter_AddRefs(mStdMarshalUnk));
}
if (FAILED(hr)) {
return hr;
}
ENSURE_HR_SUCCEEDED(hr);
}
if (!mStdMarshal) {
hr = mStdMarshalUnk->QueryInterface(IID_IMarshal, (void**)&mStdMarshal);
if (FAILED(hr)) {
return hr;
}
ENSURE_HR_SUCCEEDED(hr);
// mStdMarshal is weak, so drop its refcount
mStdMarshal->Release();
@ -668,9 +682,8 @@ Interceptor::ThreadSafeQueryInterface(REFIID aIid, IUnknown** aOutInterface)
STAUniquePtr<IDispatch> disp;
IDispatch* rawDisp = nullptr;
HRESULT hr = QueryInterfaceTarget(aIid, (void**)&rawDisp);
if (FAILED(hr)) {
return hr;
}
ENSURE_HR_SUCCEEDED(hr);
disp.reset(rawDisp);
return DispatchForwarder::Create(this, disp, aOutInterface);
}

View File

@ -688,7 +688,7 @@ struct ZoneStats
js_delete(allStrings);
}
bool initStrings(JSRuntime* rt);
bool initStrings();
void addSizes(const ZoneStats& other) {
MOZ_ASSERT(isTotals);
@ -808,7 +808,7 @@ struct CompartmentStats
js_delete(allClasses);
}
bool initClasses(JSRuntime* rt);
bool initClasses();
void addSizes(const CompartmentStats& other) {
MOZ_ASSERT(isTotals);

View File

@ -246,7 +246,7 @@ function getDuplicateVariantRE() {
// Match everything in a langtag prior to any variants, and maybe some
// of the variants as well (which makes this pattern inefficient but
// not wrong, for our purposes);
"(?:" + alphanum + "{2,8}-)+" +
"^(?:" + alphanum + "{2,8}-)+" +
// a variant, parenthesised so that we can refer back to it later;
"(" + variant + ")-" +
// zero or more subtags at least two characters long (thus stopping

View File

@ -635,7 +635,7 @@ MapObject::set(JSContext* cx, HandleObject obj, HandleValue k, HandleValue v)
MapObject*
MapObject::create(JSContext* cx, HandleObject proto /* = nullptr */)
{
auto map = cx->make_unique<ValueMap>(cx->runtime(),
auto map = cx->make_unique<ValueMap>(cx->zone(),
cx->compartment()->randomHashCodeScrambler());
if (!map || !map->init()) {
ReportOutOfMemory(cx);
@ -1318,7 +1318,7 @@ SetObject::add(JSContext* cx, HandleObject obj, HandleValue k)
SetObject*
SetObject::create(JSContext* cx, HandleObject proto /* = nullptr */)
{
auto set = cx->make_unique<ValueSet>(cx->runtime(),
auto set = cx->make_unique<ValueSet>(cx->zone(),
cx->compartment()->randomHashCodeScrambler());
if (!set || !set->init()) {
ReportOutOfMemory(cx);

View File

@ -81,11 +81,11 @@ class OrderedHashSet;
typedef OrderedHashMap<HashableValue,
HeapPtr<Value>,
HashableValue::Hasher,
RuntimeAllocPolicy> ValueMap;
ZoneAllocPolicy> ValueMap;
typedef OrderedHashSet<HashableValue,
HashableValue::Hasher,
RuntimeAllocPolicy> ValueSet;
ZoneAllocPolicy> ValueSet;
template <typename ObjectT>
class OrderedHashTableRef;
@ -130,7 +130,7 @@ class MapObject : public NativeObject {
static MOZ_MUST_USE bool iterator(JSContext *cx, IteratorKind kind, HandleObject obj,
MutableHandleValue iter);
using UnbarrieredTable = OrderedHashMap<Value, Value, UnbarrieredHashPolicy, RuntimeAllocPolicy>;
using UnbarrieredTable = OrderedHashMap<Value, Value, UnbarrieredHashPolicy, ZoneAllocPolicy>;
friend class OrderedHashTableRef<MapObject>;
static void sweepAfterMinorGC(FreeOp* fop, MapObject* mapobj);
@ -234,7 +234,7 @@ class SetObject : public NativeObject {
MutableHandleValue iter);
static MOZ_MUST_USE bool delete_(JSContext *cx, HandleObject obj, HandleValue key, bool *rval);
using UnbarrieredTable = OrderedHashSet<Value, UnbarrieredHashPolicy, RuntimeAllocPolicy>;
using UnbarrieredTable = OrderedHashSet<Value, UnbarrieredHashPolicy, ZoneAllocPolicy>;
friend class OrderedHashTableRef<SetObject>;
static void sweepAfterMinorGC(FreeOp* fop, SetObject* setobj);

View File

@ -11,7 +11,6 @@
#include "jsatom.h"
#include "builtin/SelfHostingDefines.h"
#include "gc/Zone.h"
#include "js/GCVector.h"
#include "js/Id.h"
#include "vm/NativeObject.h"

View File

@ -3056,7 +3056,7 @@ BlockOnPromise(JSContext* cx, HandleValue promiseVal, HandleObject blockedPromis
if (!GetBuiltinConstructor(cx, JSProto_Promise, &PromiseCtor))
return false;
RootedObject C(cx, SpeciesConstructor(cx, PromiseCtor, JSProto_Promise, IsPromiseSpecies));
RootedObject C(cx, SpeciesConstructor(cx, promiseObj, JSProto_Promise, IsPromiseSpecies));
if (!C)
return false;

View File

@ -9790,8 +9790,6 @@ BytecodeEmitter::emitIncOrDec(ParseNode* pn)
default:
return emitNameIncDec(pn);
}
return true;
}
// Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See

View File

@ -1662,6 +1662,18 @@ ObjectDenseElementsMayBeMarkable(NativeObject* nobj)
return mayBeMarkable;
}
static inline void
CheckForCompartmentMismatch(JSObject* obj, JSObject* obj2)
{
#ifdef DEBUG
if (MOZ_UNLIKELY(obj->compartment() != obj2->compartment())) {
fprintf(stderr, "Compartment mismatch in pointer from %s object slot to %s object\n",
obj->getClass()->name, obj2->getClass()->name);
MOZ_CRASH("Compartment mismatch");
}
#endif
}
inline void
GCMarker::processMarkStackTop(SliceBudget& budget)
{
@ -1732,7 +1744,7 @@ GCMarker::processMarkStackTop(SliceBudget& budget)
traverseEdge(obj, v.toString());
} else if (v.isObject()) {
JSObject* obj2 = &v.toObject();
MOZ_ASSERT(obj->compartment() == obj2->compartment());
CheckForCompartmentMismatch(obj, obj2);
if (mark(obj2)) {
// Save the rest of this value array for later and start scanning obj2's children.
pushValueArray(obj, vp, end);

View File

@ -458,6 +458,7 @@ class HeapCheckTracerBase : public JS::CallbackTracer
virtual void checkCell(Cell* cell) = 0;
protected:
void dumpCellInfo(Cell* cell);
void dumpCellPath();
Cell* parentCell() {
@ -555,6 +556,16 @@ HeapCheckTracerBase::traceHeap(AutoLockForExclusiveAccess& lock)
return !oom;
}
void
HeapCheckTracerBase::dumpCellInfo(Cell* cell)
{
auto kind = cell->getTraceKind();
fprintf(stderr, "%s", GCTraceKindToAscii(kind));
if (kind == JS::TraceKind::Object)
fprintf(stderr, " %s", static_cast<JSObject*>(cell)->getClass()->name);
fprintf(stderr, " %p", cell);
}
void
HeapCheckTracerBase::dumpCellPath()
{
@ -562,8 +573,9 @@ HeapCheckTracerBase::dumpCellPath()
for (int index = parentIndex; index != -1; index = stack[index].parentIndex) {
const WorkItem& parent = stack[index];
Cell* cell = parent.thing.asCell();
fprintf(stderr, " from %s %p %s edge\n",
GCTraceKindToAscii(cell->getTraceKind()), cell, name);
fprintf(stderr, " from ");
dumpCellInfo(cell);
fprintf(stderr, " %s edge\n", name);
name = parent.name;
}
fprintf(stderr, " from root %s\n", name);
@ -648,16 +660,14 @@ void
CheckGrayMarkingTracer::checkCell(Cell* cell)
{
Cell* parent = parentCell();
if (!cell->isTenured() || !parent || !parent->isTenured())
if (!parent)
return;
TenuredCell* tenuredCell = &cell->asTenured();
TenuredCell* tenuredParent = &parent->asTenured();
if (tenuredParent->isMarkedBlack() && tenuredCell->isMarkedGray())
{
if (parent->isMarkedBlack() && cell->isMarkedGray()) {
failures++;
fprintf(stderr, "Found black to gray edge to %s %p\n",
GCTraceKindToAscii(cell->getTraceKind()), cell);
fprintf(stderr, "Found black to gray edge to ");
dumpCellInfo(cell);
fprintf(stderr, "\n");
dumpCellPath();
}
}

View File

@ -104,8 +104,6 @@ Zone::init(bool isSystemArg)
void
Zone::setNeedsIncrementalBarrier(bool needs)
{
MOZ_ASSERT_IF(needs && isAtomsZone(),
!runtimeFromActiveCooperatingThread()->hasHelperThreadZones());
MOZ_ASSERT_IF(needs, canCollect());
needsIncrementalBarrier_ = needs;
}
@ -298,15 +296,14 @@ Zone::hasMarkedCompartments()
bool
Zone::canCollect()
{
// The atoms zone cannot be collected while off-thread parsing is taking
// place.
if (isAtomsZone())
return !runtimeFromAnyThread()->hasHelperThreadZones();
// Zones that will be or are currently used by other threads cannot be
// collected.
if (!isAtomsZone() && group()->createdForHelperThread())
return false;
JSRuntime* rt = runtimeFromAnyThread();
if (isAtomsZone() && rt->hasHelperThreadZones())
return false;
return true;
return !group()->createdForHelperThread();
}
void

View File

@ -252,7 +252,7 @@ struct Zone : public JS::shadow::Zone,
}
bool isCollecting() const {
MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtimeFromActiveCooperatingThread()));
MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtimeFromActiveCooperatingThread()));
return isCollectingFromAnyThread();
}
@ -435,7 +435,7 @@ struct Zone : public JS::shadow::Zone,
bool triggerGCForTooMuchMalloc() {
JSRuntime* rt = runtimeFromAnyThread();
if (CurrentThreadCanAccessRuntime(rt)) {
if (js::CurrentThreadCanAccessRuntime(rt)) {
return rt->gc.triggerZoneGC(this, JS::gcreason::TOO_MUCH_MALLOC,
gcMallocCounter.bytes(), gcMallocCounter.maxBytes());
}
@ -620,7 +620,7 @@ struct Zone : public JS::shadow::Zone,
void transferUniqueId(js::gc::Cell* tgt, js::gc::Cell* src) {
MOZ_ASSERT(src != tgt);
MOZ_ASSERT(!IsInsideNursery(tgt));
MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtimeFromActiveCooperatingThread()));
MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtimeFromActiveCooperatingThread()));
MOZ_ASSERT(js::CurrentThreadCanAccessZone(this));
MOZ_ASSERT(!uniqueIds().has(tgt));
uniqueIds().rekeyIfMoved(src, tgt);
@ -659,6 +659,28 @@ struct Zone : public JS::shadow::Zone,
// Delete an empty compartment after its contents have been merged.
void deleteEmptyCompartment(JSCompartment* comp);
/*
* This variation of calloc will call the large-allocation-failure callback
* on OOM and retry the allocation.
*/
template <typename T>
T* pod_callocCanGC(size_t numElems) {
T* p = pod_calloc<T>(numElems);
if (MOZ_LIKELY(!!p))
return p;
size_t bytes;
if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes))) {
reportAllocationOverflow();
return nullptr;
}
JSRuntime* rt = runtimeFromActiveCooperatingThread();
p = static_cast<T*>(rt->onOutOfMemoryCanGC(js::AllocFunction::Calloc, bytes));
if (!p)
return nullptr;
updateMallocCounter(bytes);
return p;
}
private:
js::ZoneGroupData<js::jit::JitZone*> jitZone_;
@ -694,7 +716,7 @@ class ZoneGroupsIter
it = rt->gc.groups().begin();
end = rt->gc.groups().end();
if (!done() && (*it)->createdForHelperThread())
if (!done() && (*it)->usedByHelperThread())
next();
}
@ -704,7 +726,7 @@ class ZoneGroupsIter
MOZ_ASSERT(!done());
do {
it++;
} while (!done() && (*it)->createdForHelperThread());
} while (!done() && (*it)->usedByHelperThread());
}
ZoneGroup* get() const {
@ -892,61 +914,47 @@ class CompartmentsIterT
typedef CompartmentsIterT<ZonesIter> CompartmentsIter;
/*
* Allocation policy that uses Zone::pod_malloc and friends, so that memory
* pressure is accounted for on the zone. This is suitable for memory associated
* with GC things allocated in the zone.
*
* Since it doesn't hold a JSContext (those may not live long enough), it can't
* report out-of-memory conditions itself; the caller must check for OOM and
* take the appropriate action.
*
* FIXME bug 647103 - replace these *AllocPolicy names.
*/
class ZoneAllocPolicy
template <typename T>
inline T*
ZoneAllocPolicy::maybe_pod_malloc(size_t numElems)
{
Zone* const zone;
return zone->maybe_pod_malloc<T>(numElems);
}
public:
MOZ_IMPLICIT ZoneAllocPolicy(Zone* zone) : zone(zone) {}
template <typename T>
inline T*
ZoneAllocPolicy::maybe_pod_calloc(size_t numElems)
{
return zone->maybe_pod_calloc<T>(numElems);
}
template <typename T>
T* maybe_pod_malloc(size_t numElems) {
return zone->maybe_pod_malloc<T>(numElems);
}
template <typename T>
inline T*
ZoneAllocPolicy::maybe_pod_realloc(T* p, size_t oldSize, size_t newSize)
{
return zone->maybe_pod_realloc<T>(p, oldSize, newSize);
}
template <typename T>
T* maybe_pod_calloc(size_t numElems) {
return zone->maybe_pod_calloc<T>(numElems);
}
template <typename T>
inline T*
ZoneAllocPolicy::pod_malloc(size_t numElems)
{
return zone->pod_malloc<T>(numElems);
}
template <typename T>
T* maybe_pod_realloc(T* p, size_t oldSize, size_t newSize) {
return zone->maybe_pod_realloc<T>(p, oldSize, newSize);
}
template <typename T>
inline T*
ZoneAllocPolicy::pod_calloc(size_t numElems)
{
return zone->pod_calloc<T>(numElems);
}
template <typename T>
T* pod_malloc(size_t numElems) {
return zone->pod_malloc<T>(numElems);
}
template <typename T>
T* pod_calloc(size_t numElems) {
return zone->pod_calloc<T>(numElems);
}
template <typename T>
T* pod_realloc(T* p, size_t oldSize, size_t newSize) {
return zone->pod_realloc<T>(p, oldSize, newSize);
}
void free_(void* p) { js_free(p); }
void reportAllocOverflow() const {}
MOZ_MUST_USE bool checkSimulatedOOM() const {
return !js::oom::ShouldFailWithOOM();
}
};
template <typename T>
inline T*
ZoneAllocPolicy::pod_realloc(T* p, size_t oldSize, size_t newSize)
{
return zone->pod_realloc<T>(p, oldSize, newSize);
}
/*
* Provides a delete policy that can be used for objects which have their

View File

@ -0,0 +1,13 @@
if (!('gczeal' in this))
quit();
if (helperThreadCount() == 0)
quit();
gczeal(15,1);
setGCCallback({
action: "majorGC",
});
gcslice(3);
var lfGlobal = newGlobal();
lfGlobal.offThreadCompileScript("");

View File

@ -29,8 +29,6 @@ using mozilla::IsInRange;
uint32_t
jit::Bailout(BailoutStack* sp, BaselineBailoutInfo** bailoutInfo)
{
AutoUnsafeCallWithABI unsafe;
JSContext* cx = TlsContext.get();
MOZ_ASSERT(bailoutInfo);
@ -106,8 +104,6 @@ uint32_t
jit::InvalidationBailout(InvalidationBailoutStack* sp, size_t* frameSizeOut,
BaselineBailoutInfo** bailoutInfo)
{
AutoUnsafeCallWithABI unsafe;
sp->checkInvariants();
JSContext* cx = TlsContext.get();

View File

@ -540,10 +540,8 @@ BaselineInspector::hasSeenDoubleResult(jsbytecode* pc)
if (stub->isUnaryArith_Fallback())
return stub->toUnaryArith_Fallback()->sawDoubleResult();
else
return stub->toBinaryArith_Fallback()->sawDoubleResult();
return false;
return stub->toBinaryArith_Fallback()->sawDoubleResult();
}
JSObject*

View File

@ -1680,7 +1680,7 @@ CanAttachDenseElementHole(JSObject* obj, bool ownProp)
// because we would have to lookup a property on the prototype instead.
do {
// The first two checks are also relevant to the receiver object.
if (obj->isIndexed())
if (obj->isNative() && obj->as<NativeObject>().isIndexed())
return false;
if (ClassCanHaveExtraProperties(obj->getClass()))
@ -3149,7 +3149,7 @@ CanAttachAddElement(JSObject* obj, bool isInit)
// or that such properties can't appear without a shape change.
do {
// The first two checks are also relevant to the receiver object.
if (obj->isIndexed())
if (obj->isNative() && obj->as<NativeObject>().isIndexed())
return false;
const Class* clasp = obj->getClass();

View File

@ -7912,7 +7912,7 @@ JitCompartment::generateStringConcatStub(JSContext* cx)
}
JitCode*
JitRuntime::generateMallocStub(JSContext* cx)
JitZone::generateMallocStub(JSContext* cx)
{
const Register regReturn = CallTempReg0;
const Register regNBytes = CallTempReg0;
@ -7928,12 +7928,12 @@ JitRuntime::generateMallocStub(JSContext* cx)
masm.PushRegsInMask(save);
const Register regTemp = regs.takeAnyGeneral();
const Register regRuntime = regTemp;
const Register regZone = regTemp;
MOZ_ASSERT(regTemp != regNBytes);
masm.setupUnalignedABICall(regTemp);
masm.movePtr(ImmPtr(cx->runtime()), regRuntime);
masm.passABIArg(regRuntime);
masm.movePtr(ImmPtr(cx->zone()), regZone);
masm.passABIArg(regZone);
masm.passABIArg(regNBytes);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, MallocWrapper));
masm.storeCallWordResult(regReturn);

View File

@ -6,6 +6,8 @@
#include "jit/Ion.h"
#include "jit/JitCompartment.h"
#include "jscompartmentinlines.h"
using namespace js;
@ -141,6 +143,12 @@ CompileZone::runtime()
return CompileRuntime::get(zone()->runtimeFromAnyThread());
}
JitCode*
CompileZone::mallocStub()
{
return zone()->jitZone()->mallocStub();
}
bool
CompileZone::isAtomsZone()
{

View File

@ -68,6 +68,8 @@ class CompileZone
CompileRuntime* runtime();
bool isAtomsZone();
JitCode* mallocStub();
#ifdef DEBUG
const void* addressOfIonBailAfter();
#endif

View File

@ -320,11 +320,6 @@ JitRuntime::initialize(JSContext* cx, AutoLockForExclusiveAccess& lock)
if (!objectGroupPreBarrier_)
return false;
JitSpew(JitSpew_Codegen, "# Emitting malloc stub");
mallocStub_ = generateMallocStub(cx);
if (!mallocStub_)
return false;
JitSpew(JitSpew_Codegen, "# Emitting free stub");
freeStub_ = generateFreeStub(cx);
if (!freeStub_)
@ -438,7 +433,7 @@ JitCompartment::~JitCompartment()
bool
JitCompartment::initialize(JSContext* cx)
{
stubCodes_ = cx->new_<ICStubCodeMap>(cx->runtime());
stubCodes_ = cx->new_<ICStubCodeMap>(cx->zone());
if (!stubCodes_)
return false;
@ -470,6 +465,13 @@ JitZone::init(JSContext* cx)
return false;
}
JitSpew(JitSpew_Codegen, "# Emitting malloc stub");
mallocStub_ = generateMallocStub(cx);
if (!mallocStub_) {
ReportOutOfMemory(cx);
return false;
}
return true;
}

View File

@ -255,8 +255,6 @@ ControlFlowGenerator::traverseBytecode()
JSOp op = JSOp(*pc);
pc += CodeSpec[op].length;
}
return true;
}
ControlFlowGenerator::ControlStatus

View File

@ -25,6 +25,8 @@ JSJitFrameIter::JSJitFrameIter(const JitActivation* activation)
current_ = activation_->bailoutData()->fp();
frameSize_ = activation_->bailoutData()->topFrameSize();
type_ = JitFrame_Bailout;
} else {
MOZ_ASSERT(!TlsContext.get()->inUnsafeCallWithABI);
}
}

View File

@ -129,8 +129,7 @@ class JitRuntime
ExclusiveAccessLockWriteOnceData<JitCode*> shapePreBarrier_;
ExclusiveAccessLockWriteOnceData<JitCode*> objectGroupPreBarrier_;
// Thunk to call malloc/free.
ExclusiveAccessLockWriteOnceData<JitCode*> mallocStub_;
// Thunk to call free.
ExclusiveAccessLockWriteOnceData<JitCode*> freeStub_;
// Thunk called to finish compilation of an IonScript.
@ -165,7 +164,6 @@ class JitRuntime
JitCode* generateBailoutHandler(JSContext* cx);
JitCode* generateInvalidator(JSContext* cx);
JitCode* generatePreBarrier(JSContext* cx, MIRType type);
JitCode* generateMallocStub(JSContext* cx);
JitCode* generateFreeStub(JSContext* cx);
JitCode* generateDebugTrapHandler(JSContext* cx);
JitCode* generateBaselineDebugModeOSRHandler(JSContext* cx, uint32_t* noFrameRegPopOffsetOut);
@ -286,10 +284,6 @@ class JitRuntime
}
}
JitCode* mallocStub() const {
return mallocStub_;
}
JitCode* freeStub() const {
return freeStub_;
}
@ -420,6 +414,9 @@ class JitZone
IcStubCodeMapGCPolicy<CacheIRStubKey>>;
BaselineCacheIRStubCodeMap baselineCacheIRStubCodes_;
// Thunk to call malloc.
WriteOnceData<JitCode*> mallocStub_;
public:
MOZ_MUST_USE bool init(JSContext* cx);
void sweep(FreeOp* fop);
@ -473,6 +470,13 @@ class JitZone
void purgeIonCacheIRStubInfo() {
ionCacheIRStubInfoSet_.finish();
}
JitCode* mallocStub() const {
return mallocStub_;
}
private:
JitCode* generateMallocStub(JSContext* cx);
};
enum class BailoutReturnStub {
@ -492,7 +496,7 @@ class JitCompartment
using ICStubCodeMap = GCHashMap<uint32_t,
ReadBarrieredJitCode,
DefaultHasher<uint32_t>,
RuntimeAllocPolicy,
ZoneAllocPolicy,
IcStubCodeMapGCPolicy<uint32_t>>;
ICStubCodeMap* stubCodes_;

View File

@ -6,6 +6,8 @@
#include "jit/LIR.h"
#include "mozilla/ScopeExit.h"
#include <ctype.h>
#include "jsprf.h"
@ -235,10 +237,18 @@ LRecoverInfo::appendDefinition(MDefinition* def)
{
MOZ_ASSERT(def->isRecoveredOnBailout());
def->setInWorklist();
auto clearWorklistFlagOnFailure = mozilla::MakeScopeExit([&] {
def->setNotInWorklist();
});
if (!appendOperands(def))
return false;
return instructions_.append(def);
if (!instructions_.append(def))
return false;
clearWorklistFlagOnFailure.release();
return true;
}
bool
@ -262,6 +272,16 @@ LRecoverInfo::appendResumePoint(MResumePoint* rp)
bool
LRecoverInfo::init(MResumePoint* rp)
{
// Before exiting this function, remove temporary flags from all definitions
// added in the vector.
auto clearWorklistFlags = mozilla::MakeScopeExit([&] {
for (MNode** it = begin(); it != end(); it++) {
if (!(*it)->isDefinition())
continue;
(*it)->toDefinition()->setNotInWorklist();
}
});
// Sort operations in the order in which we need to restore the stack. This
// implies that outer frames, as well as operations needed to recover the
// current frame, are located before the current frame. The inner-most
@ -269,14 +289,6 @@ LRecoverInfo::init(MResumePoint* rp)
if (!appendResumePoint(rp))
return false;
// Remove temporary flags from all definitions.
for (MNode** it = begin(); it != end(); it++) {
if (!(*it)->isDefinition())
continue;
(*it)->toDefinition()->setNotInWorklist();
}
MOZ_ASSERT(mir() == rp);
return true;
}

View File

@ -852,7 +852,7 @@ MacroAssembler::callMallocStub(size_t nbytes, Register result, Label* fail)
if (regNBytes != result)
push(regNBytes);
move32(Imm32(nbytes), regNBytes);
call(GetJitContext()->runtime->jitRuntime()->mallocStub());
call(GetJitContext()->compartment->zone()->mallocStub());
if (regNBytes != result) {
movePtr(regNBytes, result);
pop(regNBytes);

View File

@ -542,10 +542,10 @@ InterruptCheck(JSContext* cx)
}
void*
MallocWrapper(JSRuntime* rt, size_t nbytes)
MallocWrapper(JS::Zone* zone, size_t nbytes)
{
AutoUnsafeCallWithABI unsafe;
return rt->pod_malloc<uint8_t>(nbytes);
return zone->pod_malloc<uint8_t>(nbytes);
}
JSObject*
@ -1237,7 +1237,6 @@ bool
InitBaselineFrameForOsr(BaselineFrame* frame, InterpreterFrame* interpFrame,
uint32_t numStackValues)
{
AutoUnsafeCallWithABI unsafe;
return frame->initForOsr(interpFrame, numStackValues);
}

View File

@ -679,7 +679,7 @@ SetProperty(JSContext* cx, HandleObject obj, HandlePropertyName name, HandleValu
MOZ_MUST_USE bool
InterruptCheck(JSContext* cx);
void* MallocWrapper(JSRuntime* rt, size_t nbytes);
void* MallocWrapper(JS::Zone* zone, size_t nbytes);
JSObject* NewCallObject(JSContext* cx, HandleShape shape, HandleObjectGroup group);
JSObject* NewSingletonCallObject(JSContext* cx, HandleShape shape);
JSObject* NewStringObject(JSContext* cx, HandleString str);

View File

@ -297,7 +297,8 @@ JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type)
masm.passABIArg(r11); // BaselineFrame
masm.passABIArg(OsrFrameReg); // InterpreterFrame
masm.passABIArg(numStackValues);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::InitBaselineFrameForOsr));
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::InitBaselineFrameForOsr), MoveOp::GENERAL,
CheckUnsafeCallWithABI::DontCheckHasExitFrame);
Register jitcode = regs.takeAny();
masm.pop(jitcode);
@ -434,7 +435,8 @@ JitRuntime::generateInvalidator(JSContext* cx)
masm.passABIArg(r0);
masm.passABIArg(r1);
masm.passABIArg(r2);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, InvalidationBailout));
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, InvalidationBailout), MoveOp::GENERAL,
CheckUnsafeCallWithABI::DontCheckOther);
masm.ma_ldr(DTRAddr(sp, DtrOffImm(0)), r2);
{
@ -676,7 +678,8 @@ GenerateBailoutThunk(JSContext* cx, MacroAssembler& masm, uint32_t frameClass)
masm.passABIArg(r1);
// Sp % 8 == 0
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, Bailout));
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, Bailout), MoveOp::GENERAL,
CheckUnsafeCallWithABI::DontCheckOther);
masm.ma_ldr(DTRAddr(sp, DtrOffImm(0)), r2);
{
ScratchRegisterScope scratch(masm);

View File

@ -199,7 +199,8 @@ JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type)
masm.passABIArg(BaselineFrameReg); // BaselineFrame.
masm.passABIArg(reg_osrFrame); // InterpreterFrame.
masm.passABIArg(reg_osrNStack);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::InitBaselineFrameForOsr));
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::InitBaselineFrameForOsr), MoveOp::GENERAL,
CheckUnsafeCallWithABI::DontCheckHasExitFrame);
masm.pop(r19, BaselineFrameReg);
MOZ_ASSERT(r19 != ReturnReg);
@ -302,7 +303,8 @@ JitRuntime::generateInvalidator(JSContext* cx)
masm.passABIArg(r1);
masm.passABIArg(r2);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, InvalidationBailout));
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, InvalidationBailout), MoveOp::GENERAL,
CheckUnsafeCallWithABI::DontCheckOther);
masm.pop(r2, r1);
@ -499,7 +501,8 @@ GenerateBailoutThunk(JSContext* cx, MacroAssembler& masm, uint32_t frameClass)
masm.setupUnalignedABICall(r2);
masm.passABIArg(r0);
masm.passABIArg(r1);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, Bailout));
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, Bailout), MoveOp::GENERAL,
CheckUnsafeCallWithABI::DontCheckOther);
masm.Ldr(x2, MemOperand(masm.GetStackPointer64(), 0));
masm.addToStackPtr(Imm32(sizeOfBailoutInfo));

View File

@ -265,7 +265,8 @@ JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type)
masm.passABIArg(BaselineFrameReg); // BaselineFrame
masm.passABIArg(OsrFrameReg); // InterpreterFrame
masm.passABIArg(numStackValues);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::InitBaselineFrameForOsr));
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::InitBaselineFrameForOsr), MoveOp::GENERAL,
CheckUnsafeCallWithABI::DontCheckHasExitFrame);
regs.add(OsrFrameReg);
regs.take(JSReturnOperand);
@ -391,7 +392,8 @@ JitRuntime::generateInvalidator(JSContext* cx)
masm.passABIArg(a0);
masm.passABIArg(a1);
masm.passABIArg(a2);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, InvalidationBailout));
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, InvalidationBailout), MoveOp::GENERAL,
CheckUnsafeCallWithABI::DontCheckOther);
masm.loadPtr(Address(StackPointer, 0), a2);
masm.loadPtr(Address(StackPointer, sizeof(uintptr_t)), a1);
@ -640,7 +642,8 @@ GenerateBailoutThunk(JSContext* cx, MacroAssembler& masm, uint32_t frameClass)
masm.setupAlignedABICall();
masm.passABIArg(a0);
masm.passABIArg(a1);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, Bailout));
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, Bailout), MoveOp::GENERAL,
CheckUnsafeCallWithABI::DontCheckOther);
// Get BailoutInfo pointer
masm.loadPtr(Address(StackPointer, 0), a2);

View File

@ -282,7 +282,8 @@ JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type)
masm.passABIArg(BaselineFrameReg); // BaselineFrame
masm.passABIArg(OsrFrameReg); // InterpreterFrame
masm.passABIArg(numStackValues);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::InitBaselineFrameForOsr));
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::InitBaselineFrameForOsr), MoveOp::GENERAL,
CheckUnsafeCallWithABI::DontCheckHasExitFrame);
regs.add(OsrFrameReg);
Register jitcode = regs.takeAny();
@ -389,7 +390,8 @@ JitRuntime::generateInvalidator(JSContext* cx)
masm.passABIArg(a0);
masm.passABIArg(a1);
masm.passABIArg(a2);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, InvalidationBailout));
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, InvalidationBailout), MoveOp::GENERAL,
CheckUnsafeCallWithABI::DontCheckOther);
masm.loadPtr(Address(StackPointer, 0), a2);
masm.loadPtr(Address(StackPointer, sizeof(uintptr_t)), a1);
@ -633,7 +635,8 @@ GenerateBailoutThunk(JSContext* cx, MacroAssembler& masm, uint32_t frameClass)
masm.setupAlignedABICall();
masm.passABIArg(a0);
masm.passABIArg(a1);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, Bailout));
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, Bailout), MoveOp::GENERAL,
CheckUnsafeCallWithABI::DontCheckOther);
// Get BailoutInfo pointer
masm.loadPtr(Address(StackPointer, 0), a2);

Some files were not shown because too many files have changed in this diff Show More