mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 07:42:04 +00:00
Merge m-c to autoland, a=merge
MozReview-Commit-ID: AHxJvcR2Tpa
This commit is contained in:
commit
1ea82f66aa
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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.
|
||||
},
|
||||
|
@ -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 |
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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", () => {
|
||||
|
@ -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]
|
||||
|
@ -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.
|
||||
|
@ -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>
|
@ -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");
|
||||
});
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
1
dom/cache/test/mochitest/mochitest.ini
vendored
1
dom/cache/test/mochitest/mochitest.ini
vendored
@ -51,3 +51,4 @@ scheme=https
|
||||
[test_chrome_constructor.html]
|
||||
[test_cache_worker_gc.html]
|
||||
scheme=https
|
||||
[test_cache_tons_of_fd.html]
|
||||
|
111
dom/cache/test/mochitest/test_cache_tons_of_fd.html
vendored
Normal file
111
dom/cache/test/mochitest/test_cache_tons_of_fd.html
vendored
Normal 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>
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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]
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -17,6 +17,8 @@
|
||||
}
|
||||
else if (message.source == "iframe") {
|
||||
parent.postMessage(event.data, "*");
|
||||
} else if (message.source == "worker") {
|
||||
parent.postMessage(event.data, "*");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -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>
|
||||
|
@ -23,5 +23,7 @@
|
||||
} else {
|
||||
done(registration);
|
||||
}
|
||||
}).catch(function(e) {
|
||||
window.parent.postMessage({status: "registrationfailed"}, "*");
|
||||
});
|
||||
</script>
|
||||
|
17
dom/workers/test/serviceworkers/thirdparty/sw.js
vendored
17
dom/workers/test/serviceworkers/thirdparty/sw.js
vendored
@ -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;
|
||||
}
|
||||
});
|
||||
|
@ -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>
|
||||
|
1
dom/workers/test/serviceworkers/thirdparty/worker.js
vendored
Normal file
1
dom/workers/test/serviceworkers/thirdparty/worker.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
self.postMessage('worker-networkresponse');
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
40
editor/libeditor/tests/test_bug1399722.html
Normal file
40
editor/libeditor/tests/test_bug1399722.html
Normal 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>
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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,
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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)));
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -33,7 +33,7 @@ public:
|
||||
|
||||
protected:
|
||||
virtual ~WebRenderCanvasLayer();
|
||||
|
||||
Maybe<wr::ImageKey> mKey;
|
||||
public:
|
||||
Layer* GetLayer() override { return this; }
|
||||
void RenderLayer(wr::DisplayListBuilder& aBuilder,
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -37,7 +37,6 @@ public:
|
||||
|
||||
private:
|
||||
wr::BuiltDisplayList mBuiltDisplayList;
|
||||
nsTArray<WebRenderParentCommand> mParentCommands;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -57,6 +57,7 @@ private:
|
||||
bool SetupExternalImages();
|
||||
bool UpdateImageClient();
|
||||
void CreateWebRenderDisplayList(wr::DisplayListBuilder& aBuilder,
|
||||
wr::IpcResourceUpdateQueue& aResources,
|
||||
const StackingContextHelper& aSc);
|
||||
void ClearWrResources();
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
116
js/src/gc/Zone.h
116
js/src/gc/Zone.h
@ -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
|
||||
|
13
js/src/jit-test/tests/gc/bug-1401141.js
Normal file
13
js/src/jit-test/tests/gc/bug-1401141.js
Normal 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("");
|
||||
|
@ -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();
|
||||
|
@ -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*
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -68,6 +68,8 @@ class CompileZone
|
||||
CompileRuntime* runtime();
|
||||
bool isAtomsZone();
|
||||
|
||||
JitCode* mallocStub();
|
||||
|
||||
#ifdef DEBUG
|
||||
const void* addressOfIonBailAfter();
|
||||
#endif
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -255,8 +255,6 @@ ControlFlowGenerator::traverseBytecode()
|
||||
JSOp op = JSOp(*pc);
|
||||
pc += CodeSpec[op].length;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ControlFlowGenerator::ControlStatus
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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_;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user