Merge mozilla-central to inbound. a=merge CLOSED TREE

This commit is contained in:
shindli 2018-09-27 00:57:23 +03:00
Родитель 93da7b7bda a8d55dae12
Коммит 14c2437eec
130 изменённых файлов: 3206 добавлений и 886 удалений

Просмотреть файл

@ -358,7 +358,10 @@ MARKUPMAP(
// display style other than 'table', then create a generic table cell
// accessible, because there's no underlying table layout and thus native
// HTML table cell class doesn't work.
if (!aContext->IsHTMLTableRow()) {
// The same is true if the cell itself has CSS display:block;.
if (!aContext->IsHTMLTableRow() ||
(aElement->GetPrimaryFrame() &&
aElement->GetPrimaryFrame()->AccessibleType() != eHTMLTableCellType)) {
return new ARIAGridCellAccessibleWrap(aElement, aContext->Document());
}
if (aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::scope)) {

Просмотреть файл

@ -90,11 +90,11 @@ ARIAGridAccessible::RowCount()
Accessible*
ARIAGridAccessible::CellAt(uint32_t aRowIndex, uint32_t aColumnIndex)
{
Accessible* row = GetRowAt(aRowIndex);
Accessible* row = RowAt(aRowIndex);
if (!row)
return nullptr;
return GetCellInRowAt(row, aColumnIndex);
return CellInRowAt(row, aColumnIndex);
}
bool
@ -110,7 +110,7 @@ ARIAGridAccessible::IsColSelected(uint32_t aColIdx)
do {
if (!nsAccUtils::IsARIASelected(row)) {
Accessible* cell = GetCellInRowAt(row, aColIdx);
Accessible* cell = CellInRowAt(row, aColIdx);
if (!cell || !nsAccUtils::IsARIASelected(cell))
return false;
}
@ -125,7 +125,7 @@ ARIAGridAccessible::IsRowSelected(uint32_t aRowIdx)
if (IsARIARole(nsGkAtoms::table))
return false;
Accessible* row = GetRowAt(aRowIdx);
Accessible* row = RowAt(aRowIdx);
if(!row)
return false;
@ -147,12 +147,12 @@ ARIAGridAccessible::IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx)
if (IsARIARole(nsGkAtoms::table))
return false;
Accessible* row = GetRowAt(aRowIdx);
Accessible* row = RowAt(aRowIdx);
if(!row)
return false;
if (!nsAccUtils::IsARIASelected(row)) {
Accessible* cell = GetCellInRowAt(row, aColIdx);
Accessible* cell = CellInRowAt(row, aColIdx);
if (!cell || !nsAccUtils::IsARIASelected(cell))
return false;
}
@ -416,7 +416,7 @@ ARIAGridAccessible::SelectCol(uint32_t aColIdx)
NS_ASSERTION(NS_SUCCEEDED(rv), "SetARIASelected() Shouldn't fail!");
// Select cell at the column index.
Accessible* cell = GetCellInRowAt(row, aColIdx);
Accessible* cell = CellInRowAt(row, aColIdx);
if (cell)
SetARIASelected(cell, true);
}
@ -428,7 +428,7 @@ ARIAGridAccessible::UnselectRow(uint32_t aRowIdx)
if (IsARIARole(nsGkAtoms::table))
return;
Accessible* row = GetRowAt(aRowIdx);
Accessible* row = RowAt(aRowIdx);
if (row)
SetARIASelected(row, false);
}
@ -443,7 +443,7 @@ ARIAGridAccessible::UnselectCol(uint32_t aColIdx)
Accessible* row = nullptr;
while ((row = rowIter.Next())) {
Accessible* cell = GetCellInRowAt(row, aColIdx);
Accessible* cell = CellInRowAt(row, aColIdx);
if (cell)
SetARIASelected(cell, false);
}
@ -452,33 +452,6 @@ ARIAGridAccessible::UnselectCol(uint32_t aColIdx)
////////////////////////////////////////////////////////////////////////////////
// Protected
Accessible*
ARIAGridAccessible::GetRowAt(int32_t aRow)
{
int32_t rowIdx = aRow;
AccIterator rowIter(this, filters::GetRow);
Accessible* row = rowIter.Next();
while (rowIdx != 0 && (row = rowIter.Next()))
rowIdx--;
return row;
}
Accessible*
ARIAGridAccessible::GetCellInRowAt(Accessible* aRow, int32_t aColumn)
{
int32_t colIdx = aColumn;
AccIterator cellIter(aRow, filters::GetCell);
Accessible* cell = cellIter.Next();
while (colIdx != 0 && (cell = cellIter.Next()))
colIdx--;
return cell;
}
nsresult
ARIAGridAccessible::SetARIASelected(Accessible* aAccessible,
bool aIsSelected, bool aNotify)

Просмотреть файл

@ -52,16 +52,6 @@ public:
protected:
virtual ~ARIAGridAccessible() {}
/**
* Return row accessible at the given row index.
*/
Accessible* GetRowAt(int32_t aRow);
/**
* Return cell accessible at the given column index in the row.
*/
Accessible* GetCellInRowAt(Accessible* aRow, int32_t aColumn);
/**
* Set aria-selected attribute value on DOM node of the given accessible.
*

Просмотреть файл

@ -7,6 +7,7 @@
#include "TableAccessible.h"
#include "Accessible-inl.h"
#include "AccIterator.h"
#include "nsTableCellFrame.h"
#include "nsTableWrapperFrame.h"
@ -238,3 +239,32 @@ TableAccessible::IsProbablyLayoutTable()
false, "No layout factor strong enough, so will guess data"
);
}
Accessible*
TableAccessible::RowAt(int32_t aRow)
{
int32_t rowIdx = aRow;
AccIterator rowIter(this->AsAccessible(), filters::GetRow);
Accessible* row = rowIter.Next();
while (rowIdx != 0 && (row = rowIter.Next())) {
rowIdx--;
}
return row;
}
Accessible*
TableAccessible::CellInRowAt(Accessible* aRow, int32_t aColumn)
{
int32_t colIdx = aColumn;
AccIterator cellIter(aRow, filters::GetCell);
Accessible* cell = cellIter.Next();
while (colIdx != 0 && (cell = cellIter.Next())) {
colIdx--;
}
return cell;
}

Просмотреть файл

@ -179,6 +179,18 @@ public:
* Convert the table to an Accessible*.
*/
virtual Accessible* AsAccessible() = 0;
protected:
/**
* Return row accessible at the given row index.
*/
Accessible* RowAt(int32_t aRow);
/**
* Return cell accessible at the given column index in the row.
*/
Accessible* CellInRowAt(Accessible* aRow, int32_t aColumn);
};
} // namespace a11y

Просмотреть файл

@ -619,6 +619,14 @@ HTMLTableAccessible::CellAt(uint32_t aRowIdx, uint32_t aColIdx)
nsIContent* cellContent = tableFrame->GetCellAt(aRowIdx, aColIdx);
Accessible* cell = mDoc->GetAccessible(cellContent);
// Sometimes, the accessible returned here is a row accessible instead of
// a cell accessible, for example when a cell has CSS display:block; set.
// In such cases, iterate through the cells in this row differently to find it.
if (cell && cell->IsTableRow()) {
Accessible* row = RowAt(aRowIdx);
return CellInRowAt(row, aColIdx);
}
// XXX bug 576838: crazy tables (like table6 in tables/test_table2.html) may
// return itself as a cell what makes Orca hang.
return cell == this ? nullptr : cell;
@ -762,6 +770,9 @@ HTMLTableAccessible::UnselectCol(uint32_t aColIdx)
RemoveRowsOrColumnsFromSelection(aColIdx, TableSelection::Column, false);
}
////////////////////////////////////////////////////////////////////////////////
// HTMLTableAccessible: protected implementation
nsresult
HTMLTableAccessible::AddRowOrColumnToSelection(int32_t aIndex, TableSelection aTarget)
{

Просмотреть файл

@ -127,6 +127,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=410052
];
testTableIndexes("tableinsane6", idxes);
// ////////////////////////////////////////////////////////////////////////
// Table with a cell that has display: block; style
idxes = [
[0, 1]
];
testTableIndexes("tablewithcelldisplayblock", idxes);
SimpleTest.finish();
}
@ -405,5 +412,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=410052
</tbody>
</table>
<table id="tablewithcelldisplayblock">
<tr>
<th>a</th>
<td style="display: block;">b</td>
</tr>
</table>
</body>
</html>

Просмотреть файл

@ -66,6 +66,15 @@
testTableStruct("table4", cellsArray);
// ////////////////////////////////////////////////////////////////////////
// Table with a cell that has display: block; style
cellsArray = [
[kRowHeaderCell, kDataCell]
];
testTableStruct("table5", cellsArray);
SimpleTest.finish();
}
@ -198,5 +207,12 @@
</tbody>
</table>
<table id="table5">
<tr>
<th>a</th>
<td style="display: block;">b</td>
</tr>
</table>
</body>
</html>

Просмотреть файл

@ -218,6 +218,21 @@
] };
testAccessibleTree("table_containing_inlinetable", accTree);
// ///////////////////////////////////////////////////////////////////////
// table with a cell that has display:block
accTree =
{ TABLE: [
{ ROW: [
{ CELL: [
{ TEXT_LEAF: [ ] }
] },
{ CELL: [
{ TEXT_LEAF: [ ] }
] }
] }
] };
testAccessibleTree("table_containing_block_cell", accTree);
SimpleTest.finish();
}
@ -343,5 +358,12 @@
</tr>
</table>
</td></tr></table>
<table id="table_containing_block_cell">
<tr>
<td>Normal cell</td>
<td style="display: block;">Block cell</td>
</tr>
</table>
</body>
</html>

Просмотреть файл

@ -1498,11 +1498,6 @@ pref("browser.ping-centre.production.endpoint", "https://tiles.services.mozilla.
// Enable GMP support in the addon manager.
pref("media.gmp-provider.enabled", true);
// Enable blocking access to storage from tracking resources by default on Nightly
#ifdef NIGHTLY_BUILD
pref("network.cookie.cookieBehavior", 4 /* BEHAVIOR_REJECT_TRACKER */);
#endif
pref("browser.contentblocking.allowlist.storage.enabled", true);
pref("browser.contentblocking.global-toggle.enabled", true);

Просмотреть файл

@ -281,6 +281,12 @@ class BasePopup {
stack.appendChild(browser);
viewNode.appendChild(stack);
if (!this.extension.remote) {
// FIXME: bug 1494029 - this code used to rely on the browser binding
// accessing browser.contentWindow. This is a stopgap to continue doing
// that, but we should get rid of it in the long term.
browser.contentWindow; // eslint-disable-line no-unused-expressions
}
ExtensionParent.apiManager.emit("extension-browser-inserted", browser);

Просмотреть файл

@ -4,7 +4,6 @@ prefs =
dom.animations-api.timelines.enabled=true
support-files =
silence.ogg
head.js
head_pageAction.js
head_sessions.js
head_webNavigation.js

Просмотреть файл

@ -8,10 +8,10 @@
install-to-subdir = test-oop-extensions
tags = webextensions remote-webextensions
skip-if = !e10s
[browser_ext_popup_select.js]
skip-if = debug || os != 'win' # FIXME: re-enable on debug build (bug 1442822)
support-files =
head.js
[browser_ext_popup_select.js]
skip-if = debug || os != 'win' # FIXME: re-enable on debug build (bug 1442822)
[include:browser-common.ini]

Просмотреть файл

@ -1,6 +1,5 @@
[DEFAULT]
tags = webextensions in-process-webextensions
support-files =
head.js

Просмотреть файл

@ -1,76 +1,196 @@
var win;
var feedItem;
var container;
SimpleTest.requestCompleteLog();
ChromeUtils.import("resource://testing-common/HandlerServiceTestUtils.jsm", this);
let gHandlerService = Cc["@mozilla.org/uriloader/handler-service;1"].getService(Ci.nsIHandlerService);
let gOldMailHandlers = [];
let gDummyHandlers = [];
let gOriginalPreferredMailHandler;
let gOriginalPreferredPDFHandler;
registerCleanupFunction(function() {
function removeDummyHandlers(handlers) {
// Remove any of the dummy handlers we created.
for (let i = handlers.Count() - 1; i >= 0; i--) {
try {
if (gDummyHandlers.some(h => h.uriTemplate == handlers.queryElementAt(i, Ci.nsIWebHandlerApp).uriTemplate)) {
handlers.removeElementAt(i);
}
} catch (ex) { /* ignore non-web-app handlers */ }
}
}
// Re-add the original protocol handlers:
let mailHandlerInfo = HandlerServiceTestUtils.getHandlerInfo("mailto");
let mailHandlers = mailHandlerInfo.possibleApplicationHandlers;
for (let h of gOldMailHandlers) {
mailHandlers.appendElement(h);
}
removeDummyHandlers(mailHandlers);
mailHandlerInfo.preferredApplicationHandler = gOriginalPreferredMailHandler;
gHandlerService.store(mailHandlerInfo);
let pdfHandlerInfo = HandlerServiceTestUtils.getHandlerInfo("application/pdf");
removeDummyHandlers(pdfHandlerInfo.possibleApplicationHandlers);
pdfHandlerInfo.preferredApplicationHandler = gOriginalPreferredPDFHandler;
gHandlerService.store(pdfHandlerInfo);
gBrowser.removeCurrentTab();
});
function scrubMailtoHandlers(handlerInfo) {
// Remove extant web handlers because they have icons that
// we fetch from the web, which isn't allowed in tests.
let handlers = handlerInfo.possibleApplicationHandlers;
for (let i = handlers.Count() - 1; i >= 0; i--) {
try {
let handler = handlers.queryElementAt(i, Ci.nsIWebHandlerApp);
gOldMailHandlers.push(handler);
// If we get here, this is a web handler app. Remove it:
handlers.removeElementAt(i);
} catch (ex) {}
}
}
add_task(async function setup() {
// Create our dummy handlers
let handler1 = Cc["@mozilla.org/uriloader/web-handler-app;1"]
.createInstance(Ci.nsIWebHandlerApp);
handler1.name = "Handler 1";
handler1.uriTemplate = "https://example.com/first/%s";
let handler2 = Cc["@mozilla.org/uriloader/web-handler-app;1"]
.createInstance(Ci.nsIWebHandlerApp);
handler2.name = "Handler 2";
handler2.uriTemplate = "http://example.org/second/%s";
gDummyHandlers.push(handler1, handler2);
function substituteWebHandlers(handlerInfo) {
// Append the dummy handlers to replace them:
let handlers = handlerInfo.possibleApplicationHandlers;
handlers.appendElement(handler1);
handlers.appendElement(handler2);
gHandlerService.store(handlerInfo);
}
// Set up our mailto handler test infrastructure.
let mailtoHandlerInfo = HandlerServiceTestUtils.getHandlerInfo("mailto");
scrubMailtoHandlers(mailtoHandlerInfo);
gOriginalPreferredMailHandler = mailtoHandlerInfo.preferredApplicationHandler;
substituteWebHandlers(mailtoHandlerInfo);
// Now do the same for pdf handler:
let pdfHandlerInfo = HandlerServiceTestUtils.getHandlerInfo("application/pdf");
// PDF doesn't have built-in web handlers, so no need to scrub.
gOriginalPreferredPDFHandler = pdfHandlerInfo.preferredApplicationHandler;
substituteWebHandlers(pdfHandlerInfo);
await openPreferencesViaOpenPreferencesAPI("general", { leaveOpen: true });
info("Preferences page opened on the general pane.");
await gBrowser.selectedBrowser.contentWindow.promiseLoadHandlersList;
info("Apps list loaded.");
registerCleanupFunction(() => {
gBrowser.removeCurrentTab();
});
});
add_task(async function getFeedItem() {
win = gBrowser.selectedBrowser.contentWindow;
async function selectStandardOptions(itemToUse) {
async function selectItemInPopup(item) {
let popupShown = BrowserTestUtils.waitForEvent(popup, "popupshown");
// Synthesizing the mouse on the .actionsMenu menulist somehow just selects
// the top row. Probably something to do with the multiple layers of anon
// content - workaround by using the `.open` setter instead.
list.open = true;
await popupShown;
let popupHidden = BrowserTestUtils.waitForEvent(popup, "popuphidden");
if (typeof item == "function") {
item = item();
}
item.click();
popup.hidePopup();
await popupHidden;
return item;
}
container = win.document.getElementById("handlersView");
feedItem = container.querySelector("richlistitem[type='application/vnd.mozilla.maybe.feed']");
Assert.ok(feedItem, "feedItem is present in handlersView.");
});
let itemType = itemToUse.getAttribute("type");
// Center the item. Center rather than top so it doesn't get blocked by
// the search header.
itemToUse.scrollIntoView({block: "center"});
itemToUse.closest("richlistbox").selectItem(itemToUse);
Assert.ok(itemToUse.selected, "Should be able to select our item.");
// Force reflow to make sure it's visible and the container dropdown isn't
// hidden.
itemToUse.getBoundingClientRect().top;
let list = itemToUse.querySelector(".actionsMenu");
let popup = list.menupopup;
add_task(async function selectInternalOptionForFeed() {
// Select the item.
feedItem.scrollIntoView();
container.selectItem(feedItem);
Assert.ok(feedItem.selected, "Should be able to select our item.");
// select one of our test cases:
let handlerItem = list.querySelector("menuitem[label*='Handler 1']");
await selectItemInPopup(handlerItem);
let {preferredAction, alwaysAskBeforeHandling} = HandlerServiceTestUtils.getHandlerInfo(itemType);
Assert.notEqual(preferredAction, Ci.nsIHandlerInfo.alwaysAsk,
"Should have selected something other than 'always ask' (" + itemType + ")");
Assert.ok(!alwaysAskBeforeHandling, "Should have turned off asking before handling (" + itemType + ")");
let list = feedItem.querySelector(".actionsMenu");
// Test the alwaysAsk option
let alwaysAskItem = list.getElementsByAttribute("action", Ci.nsIHandlerInfo.alwaysAsk)[0];
await selectItemInPopup(alwaysAskItem);
Assert.equal(list.selectedItem, alwaysAskItem, "Should have selected always ask item (" + itemType + ")");
alwaysAskBeforeHandling = HandlerServiceTestUtils.getHandlerInfo(itemType).alwaysAskBeforeHandling;
Assert.ok(alwaysAskBeforeHandling, "Should have turned on asking before handling (" + itemType + ")");
// Find the "Add Live bookmarks option".
let chooseItems = list.getElementsByAttribute("action", Ci.nsIHandlerInfo.handleInternally);
Assert.equal(chooseItems.length, 1, "Should only be one action to handle internally");
let useDefaultItem = list.getElementsByAttribute("action", Ci.nsIHandlerInfo.useSystemDefault);
useDefaultItem = useDefaultItem && useDefaultItem[0];
if (useDefaultItem) {
await selectItemInPopup(useDefaultItem);
Assert.equal(list.selectedItem, useDefaultItem, "Should have selected always ask item (" + itemType + ")");
preferredAction = HandlerServiceTestUtils.getHandlerInfo(itemType).preferredAction;
Assert.equal(preferredAction, Ci.nsIHandlerInfo.useSystemDefault, "Should have selected 'use default' (" + itemType + ")");
} else {
// Whether there's a "use default" item depends on the OS, so it's not
// possible to rely on it being the case or not.
info("No 'Use default' item, so not testing (" + itemType + ")");
}
// Select the option.
let cmdEvent = win.document.createEvent("xulcommandevent");
cmdEvent.initCommandEvent("command", true, true, win, 0, false, false, false, false, null, 0);
chooseItems[0].dispatchEvent(cmdEvent);
// Select a web app item.
let webAppItems = Array.from(popup.getElementsByAttribute("action", Ci.nsIHandlerInfo.useHelperApp));
webAppItems = webAppItems.filter(item => (item.handlerApp instanceof Ci.nsIWebHandlerApp));
Assert.equal(webAppItems.length, 2, "Should have 2 web application handler. (" + itemType + ")");
Assert.notEqual(webAppItems[0].label, webAppItems[1].label, "Should have 2 different web app handlers");
let selectedItem = await selectItemInPopup(webAppItems[0]);
// Check that we display the correct result.
Assert.ok(list.selectedItem, "Should have a selected item.");
Assert.equal(list.selectedItem.getAttribute("action"),
Ci.nsIHandlerInfo.handleInternally,
"Newly selected item should be the expected one.");
});
Assert.equal(selectedItem.label, itemToUse.querySelector(".actionContainer label").value,
"Should have selected correct item (" + itemType + ")");
let {preferredApplicationHandler} = HandlerServiceTestUtils.getHandlerInfo(itemType);
preferredApplicationHandler.QueryInterface(Ci.nsIWebHandlerApp);
Assert.equal(selectedItem.handlerApp.uriTemplate, preferredApplicationHandler.uriTemplate,
"App should actually be selected in the backend. (" + itemType + ")");
// This builds on the previous selectInternalOptionForFeed task.
add_task(async function reselectInternalOptionForFeed() {
// Now select a different option in the list - use the pdf item as that doesn't
// need to load any favicons.
let anotherItem = container.querySelector("richlistitem[type='application/pdf']");
// select the other web app item
selectedItem = await selectItemInPopup(webAppItems[1]);
container.selectItem(anotherItem);
Assert.equal(selectedItem.label, itemToUse.querySelector(".actionContainer label").value,
"Should have selected correct item (" + itemType + ")");
preferredApplicationHandler = HandlerServiceTestUtils.getHandlerInfo(itemType).preferredApplicationHandler;
preferredApplicationHandler.QueryInterface(Ci.nsIWebHandlerApp);
Assert.equal(selectedItem.handlerApp.uriTemplate, preferredApplicationHandler.uriTemplate,
"App should actually be selected in the backend. (" + itemType + ")");
}
// Now select the feed item again, and check what it is displaying.
container.selectItem(feedItem);
add_task(async function checkDropdownBehavior() {
let win = gBrowser.selectedBrowser.contentWindow;
let list = feedItem.querySelector(".actionsMenu");
let container = win.document.getElementById("handlersView");
Assert.ok(list.selectedItem,
"Should have a selected item");
Assert.equal(list.selectedItem.getAttribute("action"),
Ci.nsIHandlerInfo.handleInternally,
"Selected item should still be the same as the previously selected item.");
// First check a protocol handler item.
let mailItem = container.querySelector("richlistitem[type='mailto']");
Assert.ok(mailItem, "mailItem is present in handlersView.");
await selectStandardOptions(mailItem);
// Then check a content menu item.
let pdfItem = container.querySelector("richlistitem[type='application/pdf']");
Assert.ok(pdfItem, "pdfItem is present in handlersView.");
await selectStandardOptions(pdfItem);
});
add_task(async function sortingCheck() {
win = gBrowser.selectedBrowser.contentWindow;
let win = gBrowser.selectedBrowser.contentWindow;
const handlerView = win.document.getElementById("handlersView");
const typeColumn = win.document.getElementById("typeColumn");
Assert.ok(typeColumn, "typeColumn is present in handlersView.");

Просмотреть файл

@ -35,7 +35,8 @@ function debug(s) {
function _updateCurrentContentOuterWindowID(browser) {
if (!browser.outerWindowID ||
browser.outerWindowID === _lastTopLevelWindowID) {
browser.outerWindowID === _lastTopLevelWindowID ||
browser.ownerGlobal != _trackedWindows[0]) {
return;
}

Просмотреть файл

@ -57,7 +57,9 @@ class DebugTargetList extends PureComponent {
id: "about-debugging-debug-target-list-empty"
},
dom.span(
{},
{
className: "js-debug-target-list-empty"
},
"Nothing yet."
)
);

Просмотреть файл

@ -60,7 +60,7 @@ class TemporaryExtensionAction extends PureComponent {
},
dom.button(
{
className: "aboutdebugging-button",
className: "aboutdebugging-button js-temporary-extension-remove-button",
onClick: e => this.remove()
},
"Remove",

Просмотреть файл

@ -37,7 +37,7 @@ class TemporaryExtensionInstaller extends PureComponent {
},
dom.button(
{
className: "aboutdebugging-button",
className: "aboutdebugging-button js-temporary-extension-install-button",
onClick: e => this.install()
},
"Load Temporary Add-on…"

Просмотреть файл

@ -3,13 +3,16 @@ tags = devtools
subsuite = devtools
support-files =
debug-target-pane_collapsibilities_head.js
head-addons-script.js
head.js
resources/test-temporary-extension/*
!/devtools/client/shared/test/shared-head.js
!/devtools/client/shared/test/telemetry-test-helpers.js
[browser_aboutdebugging_connect_networklocations.js]
[browser_aboutdebugging_debug-target-pane_collapsibilities_interaction.js]
[browser_aboutdebugging_debug-target-pane_collapsibilities_preference.js]
[browser_aboutdebugging_debug-target-pane_empty.js]
[browser_aboutdebugging_navigate.js]
[browser_aboutdebugging_sidebar_network_runtimes.js]
[browser_aboutdebugging_thisfirefox.js]

Просмотреть файл

@ -0,0 +1,58 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from head-addons-script.js */
"use strict";
// Load addons helpers
Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "head-addons-script.js", this);
/**
* Test that an "empty" message is displayed when there are no debug targets in a debug
* target pane.
*/
const EXTENSION_PATH = "resources/test-temporary-extension/manifest.json";
const EXTENSION_NAME = "test-temporary-extension";
add_task(async function() {
prepareCollapsibilitiesTest();
const { document, tab } = await openAboutDebugging();
info("Check that the temporary extensions pane is empty");
const temporaryExtensionPane = getDebugTargetPane("Temporary Extensions", document);
ok(!temporaryExtensionPane.querySelector(".js-debug-target-item"),
"Temporary Extensions pane contains no debug target");
info("Check an empty target pane message is displayed");
ok(temporaryExtensionPane.querySelector(".js-debug-target-list-empty"),
"An empty target list message is displayed");
info("Install a temporary extension");
await installTemporaryExtension(EXTENSION_PATH, EXTENSION_NAME, document);
info("Wait until a debug target item appears");
await waitUntil(() => temporaryExtensionPane.querySelector(".js-debug-target-item"));
info("Check the empty target pane message is no longer displayed");
ok(!temporaryExtensionPane.querySelector(".js-debug-target-list-empty"),
"The empty target list message is no longer displayed");
const temporaryExtensionItem =
temporaryExtensionPane.querySelector(".js-debug-target-item");
ok(temporaryExtensionItem, "Temporary Extensions pane now shows debug target");
info("Remove the temporary extension");
temporaryExtensionItem.querySelector(".js-temporary-extension-remove-button").click();
info("Wait until the debug target item disappears");
await waitUntil(() => !temporaryExtensionPane.querySelector(".js-debug-target-item"));
info("Check the empty target pane message is displayed again");
ok(temporaryExtensionPane.querySelector(".js-debug-target-list-empty"),
"An empty target list message is displayed again");
await removeTab(tab);
});

Просмотреть файл

@ -0,0 +1,45 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from ../../../shared/test/shared-head.js */
"use strict";
const { Management } = ChromeUtils.import("resource://gre/modules/Extension.jsm", {});
function getSupportsFile(path) {
const cr = Cc["@mozilla.org/chrome/chrome-registry;1"]
.getService(Ci.nsIChromeRegistry);
const uri = Services.io.newURI(CHROME_URL_ROOT + path);
const fileurl = cr.convertChromeURL(uri);
return fileurl.QueryInterface(Ci.nsIFileURL);
}
/**
* Install a temporary extension at the provided path, with the provided name.
* Will use a mock file picker to select the file.
*/
// eslint-disable-next-line no-unused-vars
async function installTemporaryExtension(path, name, document) {
// Mock the file picker to select a test addon
const MockFilePicker = SpecialPowers.MockFilePicker;
MockFilePicker.init(window);
const file = getSupportsFile(path);
MockFilePicker.setFiles([file.file]);
const onAddonInstalled = new Promise(done => {
Management.on("startup", function listener(event, extension) {
if (extension.name != name) {
return;
}
Management.off("startup", listener);
done();
});
});
// Trigger the file picker by clicking on the button
document.querySelector(".js-temporary-extension-install-button").click();
info("Wait for addon to be installed");
await onAddonInstalled;
}

Просмотреть файл

@ -0,0 +1,13 @@
{
"manifest_version": 2,
"name": "test-temporary-extension",
"version": "1.0",
"applications": {
"gecko": {
"id": "test-temporary-extension@mozilla.org"
}
},
"background": {
"scripts": ["script.js"]
}
}

Просмотреть файл

@ -0,0 +1,9 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* eslint-env browser */
/* global browser */
"use strict";
document.body.innerText = "Background Page Body Test Content";

Просмотреть файл

@ -162,6 +162,13 @@
overflow-x: auto;
}
/* If there is a source editor shows up in the last row of TreeView,
* its height should not collapse into zero
*/
.network-monitor .tree-container .treeTable tr:last-child.editor-row-container {
overflow: visible;
}
.network-monitor .source-editor-mount {
width: 100%;
height: 100%;

Просмотреть файл

@ -68,6 +68,8 @@ add_task(async function() {
const jsonView = tabpanel.querySelector(".tree-section .treeLabel") || {};
is(jsonView.textContent === L10N.getStr("jsonScopeName"), true,
"The response json view has the intended visibility.");
is(tabpanel.querySelector(".editor-row-container").clientHeight !== 0, true,
"The source editor container has visible height.");
is(tabpanel.querySelector(".CodeMirror-code") === null, false,
"The response editor has the intended visibility.");
is(tabpanel.querySelector(".response-image-box") === null, true,

Просмотреть файл

@ -1141,17 +1141,30 @@ class JSTerm extends Component {
if (this._autocompleteQuery && input.startsWith(this._autocompleteQuery)) {
let filterBy = input;
// Find the last non-alphanumeric other than "_", ":", or "$" if it exists.
const lastNonAlpha = input.match(/[^a-zA-Z0-9_$:][a-zA-Z0-9_$:]*$/);
// If input contains non-alphanumerics, use the part after the last one
// to filter the cache.
if (lastNonAlpha) {
filterBy = input.substring(input.lastIndexOf(lastNonAlpha) + 1);
if (this._autocompleteCache.isElementAccess) {
// if we're performing an element access, we can simply retrieve whatever comes
// after the last opening bracket.
filterBy = input.substring(input.lastIndexOf("[") + 1);
} else {
// Find the last non-alphanumeric other than "_", ":", or "$" if it exists.
const lastNonAlpha = input.match(/[^a-zA-Z0-9_$:][a-zA-Z0-9_$:]*$/);
// If input contains non-alphanumerics, use the part after the last one
// to filter the cache.
if (lastNonAlpha) {
filterBy = input.substring(input.lastIndexOf(lastNonAlpha) + 1);
}
}
const stripWrappingQuotes = s => s.replace(/^['"`](.+(?=['"`]$))['"`]$/g, "$1");
const filterByLc = filterBy.toLocaleLowerCase();
const looseMatching = !filterBy || filterBy[0].toLocaleLowerCase() === filterBy[0];
const newList = this._autocompleteCache.filter(l => {
const needStripQuote = this._autocompleteCache.isElementAccess
&& !/^[`"']/.test(filterBy);
const newList = this._autocompleteCache.matches.filter(l => {
if (needStripQuote) {
l = stripWrappingQuotes(l);
}
if (looseMatching) {
return l.toLocaleLowerCase().startsWith(filterByLc);
}
@ -1161,7 +1174,8 @@ class JSTerm extends Component {
this._receiveAutocompleteProperties(null, {
matches: newList,
matchProp: filterBy
matchProp: filterBy,
isElementAccess: this._autocompleteCache.isElementAccess,
});
return;
}
@ -1191,28 +1205,49 @@ class JSTerm extends Component {
this.currentAutoCompletionRequestId = null;
// Cache whatever came from the server if the last char is
// alphanumeric or '.'
// alphanumeric, '.' or '['.
const inputUntilCursor = this.getInputValueBeforeCursor();
if (requestId != null && /[a-zA-Z0-9.]$/.test(inputUntilCursor)) {
this._autocompleteCache = message.matches;
if (requestId != null && /[a-zA-Z0-9.\[]$/.test(inputUntilCursor)) {
this._autocompleteCache = {
matches: message.matches,
matchProp: message.matchProp,
isElementAccess: message.isElementAccess,
};
this._autocompleteQuery = inputUntilCursor;
}
const {matches, matchProp} = message;
const {matches, matchProp, isElementAccess} = message;
if (!matches.length) {
this.clearCompletion();
this.emit("autocomplete-updated");
return;
}
const items = matches.map(match => ({
preLabel: match.substring(0, matchProp.length),
label: match
}));
const items = matches.map(label => {
let preLabel = label.substring(0, matchProp.length);
// If the user is performing an element access, and if they did not typed a quote,
// then we need to adjust the preLabel to match the quote from the label + what
// the user entered.
if (isElementAccess && /^['"`]/.test(matchProp) === false) {
preLabel = label.substring(0, matchProp.length + 1);
}
return {preLabel, label, isElementAccess};
});
if (items.length > 0) {
const suffix = items[0].label.substring(matchProp.length);
const {preLabel, label} = items[0];
let suffix = label.substring(preLabel.length);
if (isElementAccess) {
if (!matchProp) {
suffix = label;
}
const inputAfterCursor = this.getInputValue().substring(inputUntilCursor.length);
// If there's not a bracket after the cursor, add it to the completionText.
if (!inputAfterCursor.trimLeft().startsWith("]")) {
suffix = suffix + "]";
}
}
this.setAutoCompletionText(suffix);
}
@ -1245,7 +1280,7 @@ class JSTerm extends Component {
if (this.editor) {
popupAlignElement = this.node.querySelector(".CodeMirror-cursor");
// We need to show the popup at the ".".
// We need to show the popup at the "." or "[".
xOffset = -1 * matchProp.length * this._inputCharWidth;
yOffset = 5;
} else if (this.inputNode) {
@ -1274,7 +1309,23 @@ class JSTerm extends Component {
onAutocompleteSelect() {
const {selectedItem} = this.autocompletePopup;
if (selectedItem) {
const suffix = selectedItem.label.substring(selectedItem.preLabel.length);
const {preLabel, label, isElementAccess} = selectedItem;
let suffix = label.substring(preLabel.length);
// If the user is performing an element access, we need to check if we should add
// starting and ending quotes, as well as a closing bracket.
if (isElementAccess) {
const inputBeforeCursor = this.getInputValueBeforeCursor();
if (inputBeforeCursor.trim().endsWith("[")) {
suffix = label;
}
const inputAfterCursor = this.getInputValue().substring(inputBeforeCursor.length);
// If there's no closing bracket after the cursor, add it to the completionText.
if (!inputAfterCursor.trimLeft().startsWith("]")) {
suffix = suffix + "]";
}
}
this.setAutoCompletionText(suffix);
} else {
this.setAutoCompletionText("");
@ -1306,10 +1357,6 @@ class JSTerm extends Component {
/**
* Accept the proposed input completion.
*
* @return boolean
* True if there was a selected completion item and the input value
* was updated, false otherwise.
*/
acceptProposedCompletion() {
let completionText = this.getAutoCompletionText();
@ -1320,8 +1367,27 @@ class JSTerm extends Component {
// autocomplete to `document`, but the autocompletion text only shows `t`).
if (this.autocompletePopup.isOpen && this.autocompletePopup.selectedItem) {
const {selectedItem} = this.autocompletePopup;
completionText = selectedItem.label;
numberOfCharsToReplaceCharsBeforeCursor = selectedItem.preLabel.length;
const {label, preLabel, isElementAccess} = selectedItem;
completionText = label;
numberOfCharsToReplaceCharsBeforeCursor = preLabel.length;
// If the user is performing an element access, we need to check if we should add
// starting and ending quotes, as well as a closing bracket.
if (isElementAccess) {
const inputBeforeCursor = this.getInputValueBeforeCursor();
const lastOpeningBracketIndex = inputBeforeCursor.lastIndexOf("[");
if (lastOpeningBracketIndex > -1) {
numberOfCharsToReplaceCharsBeforeCursor =
inputBeforeCursor.substring(lastOpeningBracketIndex + 1).length;
}
const inputAfterCursor = this.getInputValue().substring(inputBeforeCursor.length);
// If there's not a bracket after the cursor, add it.
if (!inputAfterCursor.trimLeft().startsWith("]")) {
completionText = completionText + "]";
}
}
}
this.clearCompletion();

Просмотреть файл

@ -205,6 +205,8 @@ skip-if = verify
[browser_jsterm_autocomplete-properties-with-non-alphanumeric-names.js]
[browser_jsterm_await_paused.js]
[browser_jsterm_await.js]
[browser_jsterm_completion_bracket_cached_results.js]
[browser_jsterm_completion_bracket.js]
[browser_jsterm_completion_case_sensitivity.js]
[browser_jsterm_completion.js]
[browser_jsterm_content_defined_helpers.js]

Просмотреть файл

@ -94,6 +94,29 @@ async function performTests() {
ok(!getPopupLabels(popup).includes("docfoobar"),
"autocomplete cached results do not contain docfoobar. list has not been updated");
info("Ensure filtering from the cache does work");
await jsterm.execute(`
window.testObject = Object.create(null);
window.testObject.zz = "zz";
window.testObject.zzz = "zzz";
window.testObject.zzzz = "zzzz";
`);
await jstermComplete("window.testObject.");
await jstermComplete("window.testObject.z");
is(getPopupLabels(popup).join("-"), "zz-zzz-zzzz", "results are the expected ones");
onUpdated = jsterm.once("autocomplete-updated");
EventUtils.sendString("z");
await onUpdated;
is(getPopupLabels(popup).join("-"), "zz-zzz-zzzz",
"filtering from the cache works - step 1");
onUpdated = jsterm.once("autocomplete-updated");
EventUtils.sendString("z");
await onUpdated;
is(getPopupLabels(popup).join("-"), "zzz-zzzz",
"filtering from the cache works - step 2");
}
function getPopupLabels(popup) {

Просмотреть файл

@ -33,12 +33,12 @@ async function performTests() {
await onPopupOpen;
ok(popup.isOpen, "popup is open");
is(popup.itemCount, jsterm._autocompleteCache.length, "popup.itemCount is correct");
ok(jsterm._autocompleteCache.includes("addEventListener"),
const cacheMatches = jsterm._autocompleteCache.matches;
is(popup.itemCount, cacheMatches.length, "popup.itemCount is correct");
ok(cacheMatches.includes("addEventListener"),
"addEventListener is in the list of suggestions");
ok(jsterm._autocompleteCache.includes("bgColor"),
"bgColor is in the list of suggestions");
ok(jsterm._autocompleteCache.includes("ATTRIBUTE_NODE"),
ok(cacheMatches.includes("bgColor"), "bgColor is in the list of suggestions");
ok(cacheMatches.includes("ATTRIBUTE_NODE"),
"ATTRIBUTE_NODE is in the list of suggestions");
const onPopupClose = popup.once("popup-closed");

Просмотреть файл

@ -0,0 +1,212 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that code completion works properly with `[`
"use strict";
const TEST_URI = `data:text/html;charset=utf8,<p>test [ completion.
<script>
window.testObject = Object.create(null, Object.getOwnPropertyDescriptors({
bar: 0,
dataTest: 1,
"data-test": 2,
'da"ta"test': 3,
"da\`ta\`test": 4,
"da'ta'test": 5,
"DATA-TEST": 6,
}));
</script>`;
add_task(async function() {
// Run test with legacy JsTerm
await pushPref("devtools.webconsole.jsterm.codeMirror", false);
await performTests();
// And then run it with the CodeMirror-powered one.
await pushPref("devtools.webconsole.jsterm.codeMirror", true);
await performTests();
});
async function performTests() {
const {jsterm} = await openNewTabAndConsole(TEST_URI);
await testInputs(jsterm);
await testCompletionTextUpdateOnPopupNavigate(jsterm);
await testAcceptCompletionExistingClosingBracket(jsterm);
}
async function testInputs(jsterm) {
const tests = [{
description: "Check that the popup is opened when typing `[`",
input: "window.testObject[",
expectedItems: [
`"bar"`,
`"da'ta'test"`,
`"da\\"ta\\"test"`,
`"da\`ta\`test"`,
`"data-test"`,
`"dataTest"`,
`"DATA-TEST"`,
],
expectedCompletionText: `"bar"]`,
expectedInputAfterCompletion: `window.testObject["bar"]`
}, {
description: "Test that the list can be filtered even without quote",
input: "window.testObject[d",
expectedItems: [
`"da'ta'test"`,
`"da\\"ta\\"test"`,
`"da\`ta\`test"`,
`"data-test"`,
`"dataTest"`,
`"DATA-TEST"`,
],
expectedCompletionText: `a'ta'test"]`,
expectedInputAfterCompletion: `window.testObject["da'ta'test"]`,
}, {
description: "Test filtering with quote and string",
input: `window.testObject["d`,
expectedItems: [
`"da'ta'test"`,
`"da\\"ta\\"test"`,
`"da\`ta\`test"`,
`"data-test"`,
`"dataTest"`,
`"DATA-TEST"`,
],
expectedCompletionText: `a'ta'test"]`,
expectedInputAfterCompletion: `window.testObject["da'ta'test"]`,
}, {
description: "Test filtering with simple quote and string",
input: `window.testObject['d`,
expectedItems: [
`'da"ta"test'`,
`'da\\'ta\\'test'`,
`'da\`ta\`test'`,
`'data-test'`,
`'dataTest'`,
`'DATA-TEST'`,
],
expectedCompletionText: `a"ta"test']`,
expectedInputAfterCompletion: `window.testObject['da"ta"test']`,
}, {
description: "Test filtering with template literal and string",
input: "window.testObject[`d",
expectedItems: [
"`da\"ta\"test`",
"`da'ta'test`",
"`da\\`ta\\`test`",
"`data-test`",
"`dataTest`",
"`DATA-TEST`",
],
expectedCompletionText: 'a"ta"test`]',
expectedInputAfterCompletion: 'window.testObject[`da"ta"test`]',
}, {
description: "Test that filtering is case insensitive",
input: "window.testObject[data-t",
expectedItems: [
`"data-test"`,
`"DATA-TEST"`,
],
expectedCompletionText: `est"]`,
expectedInputAfterCompletion: `window.testObject["data-test"]`,
}, {
description:
"Test that filtering without quote displays the popup when there's only 1 match",
input: "window.testObject[DATA-",
expectedItems: [
`"DATA-TEST"`
],
expectedCompletionText: `TEST"]`,
expectedInputAfterCompletion: `window.testObject["DATA-TEST"]`,
}];
for (const test of tests) {
await testInput(jsterm, test);
}
}
async function testInput(jsterm, {
description,
input,
expectedItems,
expectedCompletionText,
expectedInputAfterCompletion
}) {
const {autocompletePopup} = jsterm;
info(`${description} - test popup opening`);
const onPopUpOpen = autocompletePopup.once("popup-opened");
EventUtils.sendString(input);
await onPopUpOpen;
is(getAutocompletePopupLabels(autocompletePopup).join("|"), expectedItems.join("|"),
`${description} - popup has expected item, in expected order`);
checkJsTermCompletionValue(jsterm, " ".repeat(input.length) + expectedCompletionText,
`${description} - completeNode has expected value`);
info(`${description} - test accepting completion`);
const onPopupClose = autocompletePopup.once("popup-closed");
EventUtils.synthesizeKey("KEY_Tab");
await onPopupClose;
checkJsTermValueAndCursor(jsterm, expectedInputAfterCompletion + "|",
`${description} - input was completed as expected`);
checkJsTermCompletionValue(jsterm, "", `${description} - completeNode is empty`);
jsterm.setInputValue("");
}
async function testCompletionTextUpdateOnPopupNavigate(jsterm) {
const {autocompletePopup} = jsterm;
info("Test that navigating the popup list update the completionText as expected");
const onPopUpOpen = autocompletePopup.once("popup-opened");
const input = `window.testObject[data`;
EventUtils.sendString(input);
await onPopUpOpen;
is(getAutocompletePopupLabels(autocompletePopup).join("|"),
`"data-test"|"dataTest"|"DATA-TEST"`, `popup has expected items, in expected order`);
checkJsTermCompletionValue(jsterm, " ".repeat(input.length) + `-test"]`,
`completeNode has expected value`);
EventUtils.synthesizeKey("KEY_ArrowDown");
checkJsTermCompletionValue(jsterm, " ".repeat(input.length) + `Test"]`,
`completeNode has expected value`);
EventUtils.synthesizeKey("KEY_ArrowDown");
checkJsTermCompletionValue(jsterm, " ".repeat(input.length) + `-TEST"]`,
`completeNode has expected value`);
const onPopupClose = autocompletePopup.once("popup-closed");
EventUtils.synthesizeKey("KEY_Tab");
await onPopupClose;
checkJsTermValueAndCursor(jsterm, `window.testObject["DATA-TEST"]|`,
`input was completed as expected after navigating the popup`);
}
async function testAcceptCompletionExistingClosingBracket(jsterm) {
const {autocompletePopup} = jsterm;
info("Check that accepting completion when there's a closing bracket does not append " +
"another closing bracket");
await setInputValueForAutocompletion(jsterm, "window.testObject[]", -1);
const onPopUpOpen = autocompletePopup.once("popup-opened");
EventUtils.sendString("b");
await onPopUpOpen;
is(getAutocompletePopupLabels(autocompletePopup).join("|"), `"bar"`,
`popup has expected item`);
const onPopupClose = autocompletePopup.once("popup-closed");
EventUtils.synthesizeKey("KEY_Tab");
await onPopupClose;
checkJsTermValueAndCursor(jsterm, `window.testObject["bar"|]`,
`input was completed as expected, without adding a closing bracket`);
}
function getAutocompletePopupLabels(autocompletePopup) {
return autocompletePopup.items.map(i => i.label);
}

Просмотреть файл

@ -0,0 +1,151 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that code completion works properly with `[` and cached results
"use strict";
const TEST_URI = `data:text/html;charset=utf8,<p>test [ completion cached results.
<script>
window.testObject = Object.create(null, Object.getOwnPropertyDescriptors({
bar: 0,
dataTest: 1,
"data-test": 2,
'da"ta"test': 3,
"da\`ta\`test": 4,
"da'ta'test": 5,
"DATA-TEST": 6,
}));
</script>`;
add_task(async function() {
// Run test with legacy JsTerm
await pushPref("devtools.webconsole.jsterm.codeMirror", false);
await performTests();
// And then run it with the CodeMirror-powered one.
await pushPref("devtools.webconsole.jsterm.codeMirror", true);
await performTests();
});
async function performTests() {
const {jsterm} = await openNewTabAndConsole(TEST_URI);
info("Test that the autocomplete cache works with brackets");
const {autocompletePopup} = jsterm;
const tests = [{
description: "Test that it works if the user did not type a quote",
initialInput: `window.testObject[dat`,
expectedItems: [
`"data-test"`,
`"dataTest"`,
`"DATA-TEST"`,
],
expectedCompletionText: `a-test"]`,
sequence: [{
char: "a",
expectedItems: [
`"data-test"`,
`"dataTest"`,
`"DATA-TEST"`,
],
expectedCompletionText: `-test"]`,
}, {
char: "-",
expectedItems: [
`"data-test"`,
`"DATA-TEST"`
],
expectedCompletionText: `test"]`,
}, {
char: "t",
expectedItems: [
`"data-test"`,
`"DATA-TEST"`
],
expectedCompletionText: `est"]`,
}, {
char: "e",
expectedItems: [
`"data-test"`,
`"DATA-TEST"`
],
expectedCompletionText: `st"]`,
}]
}, {
description: "Test that it works if the user did type a quote",
initialInput: `window.testObject['dat`,
expectedItems: [
`'data-test'`,
`'dataTest'`,
`'DATA-TEST'`,
],
expectedCompletionText: `a-test']`,
sequence: [{
char: "a",
expectedItems: [
`'data-test'`,
`'dataTest'`,
`'DATA-TEST'`,
],
expectedCompletionText: `-test']`,
}, {
char: "-",
expectedItems: [
`'data-test'`,
`'DATA-TEST'`
],
expectedCompletionText: `test']`,
}, {
char: "t",
expectedItems: [
`'data-test'`,
`'DATA-TEST'`
],
expectedCompletionText: `est']`,
}, {
char: "e",
expectedItems: [
`'data-test'`,
`'DATA-TEST'`
],
expectedCompletionText: `st']`,
}]
}];
for (const test of tests) {
info(test.description);
const onPopUpOpen = autocompletePopup.once("popup-opened");
EventUtils.sendString(test.initialInput);
await onPopUpOpen;
is(getAutocompletePopupLabels(autocompletePopup).join("|"),
test.expectedItems.join("|"), `popup has expected items, in expected order`);
checkJsTermCompletionValue(jsterm,
" ".repeat(test.initialInput.length) + test.expectedCompletionText,
`completeNode has expected value`);
for (const {char, expectedItems, expectedCompletionText} of test.sequence) {
const onPopupUpdate = jsterm.once("autocomplete-updated");
EventUtils.sendString(char);
await onPopupUpdate;
is(getAutocompletePopupLabels(autocompletePopup).join("|"), expectedItems.join("|"),
`popup has expected items, in expected order`);
checkJsTermCompletionValue(jsterm,
" ".repeat(jsterm.getInputValue().length) + expectedCompletionText,
`completeNode has expected value`);
}
jsterm.setInputValue("");
const onPopupClose = autocompletePopup.once("popup-closed");
EventUtils.synthesizeKey("KEY_Escape");
await onPopupClose;
}
}
function getAutocompletePopupLabels(autocompletePopup) {
return autocompletePopup.items.map(i => i.label);
}

Просмотреть файл

@ -507,6 +507,98 @@ const proto = {
return { descriptor: this._propertyDescriptor(name) };
},
/**
* Handle a protocol request to provide the value of the object's
* specified property.
*
* Note: Since this will evaluate getters, it can trigger execution of
* content code and may cause side effects. This endpoint should only be used
* when you are confident that the side-effects will be safe, or the user
* is expecting the effects.
*
* @param {string} name
* The property we want the value of.
*/
propertyValue: function(name) {
if (!name) {
return this.throwError("missingParameter", "no property name was specified");
}
const value = this.obj.getProperty(name);
return { value: this._buildCompletion(value) };
},
/**
* Handle a protocol request to evaluate a function and provide the value of
* the result.
*
* Note: Since this will evaluate the function, it can trigger execution of
* content code and may cause side effects. This endpoint should only be used
* when you are confident that the side-effects will be safe, or the user
* is expecting the effects.
*
* @param {any} context
* The 'this' value to call the function with.
* @param {Array<any>} args
* The array of un-decoded actor objects, or primitives.
*/
apply: function(context, args) {
if (!this.obj.callable) {
return this.throwError("notCallable", "debugee object is not callable");
}
const debugeeContext = this._getValueFromGrip(context);
const debugeeArgs = args && args.map(this._getValueFromGrip, this);
const value = this.obj.apply(debugeeContext, debugeeArgs);
return { value: this._buildCompletion(value) };
},
_getValueFromGrip(grip) {
if (typeof grip !== "object" || !grip) {
return grip;
}
if (typeof grip.actor !== "string") {
return this.throwError("invalidGrip", "grip argument did not include actor ID");
}
const actor = this.conn.getActor(grip.actor);
if (!actor) {
return this.throwError("unknownActor", "grip actor did not match a known object");
}
return actor.obj;
},
/**
* Converts a Debugger API completion value record into an eqivalent
* object grip for use by the API.
*
* See https://developer.mozilla.org/en-US/docs/Tools/Debugger-API/Conventions#completion-values
* for more specifics on the expected behavior.
*/
_buildCompletion(value) {
let completionGrip = null;
// .apply result will be falsy if the script being executed is terminated
// via the "slow script" dialog.
if (value) {
completionGrip = {};
if ("return" in value) {
completionGrip.return = this.hooks.createValueGrip(value.return);
}
if ("throw" in value) {
completionGrip.throw = this.hooks.createValueGrip(value.throw);
}
}
return completionGrip;
},
/**
* Handle a protocol request to provide the display string for the object.
*/

Просмотреть файл

@ -1610,7 +1610,13 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
getGripDepth: () => this._gripDepth,
incrementGripDepth: () => this._gripDepth++,
decrementGripDepth: () => this._gripDepth--,
createValueGrip: v => createValueGrip(v, this._pausePool, this.pauseObjectGrip),
createValueGrip: v => {
if (this._pausePool) {
return createValueGrip(v, this._pausePool, this.pauseObjectGrip);
}
return createValueGrip(v, this.threadLifetimePool, this.objectGrip);
},
sources: () => this.sources,
createEnvironmentActor: (e, p) => this.createEnvironmentActor(e, p),
promote: () => this.threadObjectGrip(actor),

Просмотреть файл

@ -1137,6 +1137,8 @@ WebConsoleActor.prototype =
let hadDebuggee = false;
let matches = [];
let matchProp;
let isElementAccess;
const reqText = request.text.substr(0, request.cursor);
if (isCommand(reqText)) {
@ -1175,12 +1177,15 @@ WebConsoleActor.prototype =
matches = result.matches || new Set();
matchProp = result.matchProp;
isElementAccess = result.isElementAccess;
// We consider '$' as alphanumeric because it is used in the names of some
// helper functions; we also consider whitespace as alphanum since it should not
// be seen as break in the evaled string.
const lastNonAlphaIsDot = /[.][a-zA-Z0-9$\s]*$/.test(reqText);
if (!lastNonAlphaIsDot) {
// We only return command when we are not dealing with a property or element access.
if (!lastNonAlphaIsDot && !isElementAccess) {
this._getWebConsoleCommandsCache().forEach(n => {
// filter out `screenshot` command as it is inaccessible without the `:` prefix
if (n !== "screenshot" && n.startsWith(result.matchProp)) {
@ -1193,8 +1198,11 @@ WebConsoleActor.prototype =
// display `document` then `Document` as we loosely match the user input if the
// first letter they typed was lowercase).
matches = Array.from(matches).sort((a, b) => {
const lA = a[0].toLocaleLowerCase() === a[0];
const lB = b[0].toLocaleLowerCase() === b[0];
const startingQuoteRegex = /^('|"|`)/;
const aFirstMeaningfulChar = startingQuoteRegex.test(a) ? a[1] : a[0];
const bFirstMeaningfulChar = startingQuoteRegex.test(b) ? b[1] : b[0];
const lA = aFirstMeaningfulChar.toLocaleLowerCase() === aFirstMeaningfulChar;
const lB = bFirstMeaningfulChar.toLocaleLowerCase() === bFirstMeaningfulChar;
if (lA === lB) {
return a < b ? -1 : 1;
}
@ -1206,6 +1214,7 @@ WebConsoleActor.prototype =
from: this.actorID,
matches,
matchProp,
isElementAccess: isElementAccess === true,
};
},

Просмотреть файл

@ -0,0 +1,154 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* eslint-disable no-shadow, max-nested-callbacks */
"use strict";
async function run_test() {
try {
do_test_pending();
await run_test_with_server(DebuggerServer);
await run_test_with_server(WorkerDebuggerServer);
} finally {
do_test_finished();
}
}
async function run_test_with_server(server) {
initTestDebuggerServer(server);
const debuggee = addTestGlobal("test-grips", server);
debuggee.eval(`
function stopMe(arg1) {
debugger;
}
`);
const dbgClient = new DebuggerClient(server.connectPipe());
await dbgClient.connect();
const [,, threadClient] = await attachTestTabAndResume(dbgClient, "test-grips");
await test_object_grip(debuggee, threadClient);
await dbgClient.close();
}
async function test_object_grip(debuggee, threadClient) {
await assert_object_argument(
debuggee,
threadClient,
`
stopMe({
obj1: {},
obj2: {},
context(arg) {
return this === arg ? "correct context" : "wrong context";
},
sum(...parts) {
return parts.reduce((acc, v) => acc + v, 0);
},
error() {
throw "an error";
},
});
`,
async objClient => {
const obj1 = (await objClient.getPropertyValue("obj1")).value.return;
const obj2 = (await objClient.getPropertyValue("obj2")).value.return;
const context = threadClient.pauseGrip(
(await objClient.getPropertyValue("context")).value.return,
);
const sum = threadClient.pauseGrip(
(await objClient.getPropertyValue("sum")).value.return,
);
const error = threadClient.pauseGrip(
(await objClient.getPropertyValue("error")).value.return,
);
assert_response(await context.apply(obj1, [obj1]), {
return: "correct context",
});
assert_response(await context.apply(obj2, [obj2]), {
return: "correct context",
});
assert_response(await context.apply(obj1, [obj2]), {
return: "wrong context",
});
assert_response(await context.apply(obj2, [obj1]), {
return: "wrong context",
});
// eslint-disable-next-line no-useless-call
assert_response(await sum.apply(null, [1, 2, 3, 4, 5, 6, 7]), {
return: 1 + 2 + 3 + 4 + 5 + 6 + 7,
});
// eslint-disable-next-line no-useless-call
assert_response(await error.apply(null, []), {
throw: "an error",
});
},
);
}
function assert_object_argument(debuggee, threadClient, code, objectHandler) {
return eval_and_resume(debuggee, threadClient, code, async frame => {
const arg1 = frame.arguments[0];
Assert.equal(arg1.class, "Object");
await objectHandler(threadClient.pauseGrip(arg1));
});
}
function eval_and_resume(debuggee, threadClient, code, callback) {
return new Promise((resolve, reject) => {
wait_for_pause(threadClient, callback).then(resolve, reject);
// This synchronously blocks until 'threadClient.resume()' above runs
// because the 'paused' event runs everthing in a new event loop.
debuggee.eval(code);
});
}
function wait_for_pause(threadClient, callback = () => {}) {
return new Promise((resolve, reject) => {
threadClient.addOneTimeListener("paused", function(event, packet) {
(async () => {
try {
return await callback(packet.frame);
} finally {
await threadClient.resume();
}
})().then(resolve, reject);
});
});
}
function assert_response({ value }, expected) {
assert_completion(value, expected);
}
function assert_completion(value, expected) {
if (expected && "return" in expected) {
assert_value(value.return, expected.return);
}
if (expected && "throw" in expected) {
assert_value(value.throw, expected.throw);
}
if (!expected) {
assert_value(value, expected);
}
}
function assert_value(actual, expected) {
Assert.equal(typeof actual, typeof expected);
if (typeof expected === "object") {
// Note: We aren't using deepEqual here because we're only doing a cursory
// check of a few properties, not a full comparison of the result, since
// the full outputs includes stuff like preview info that we don't need.
for (const key of Object.keys(expected)) {
assert_value(actual[key], expected[key]);
}
} else {
Assert.equal(actual, expected);
}
}

Просмотреть файл

@ -0,0 +1,88 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* eslint-disable no-shadow, max-nested-callbacks */
"use strict";
async function run_test() {
try {
do_test_pending();
await run_test_with_server(DebuggerServer);
await run_test_with_server(WorkerDebuggerServer);
} finally {
do_test_finished();
}
}
async function run_test_with_server(server) {
initTestDebuggerServer(server);
const debuggee = addTestGlobal("test-grips", server);
debuggee.eval(`
function stopMe(arg1) {
debugger;
}
`);
const dbgClient = new DebuggerClient(server.connectPipe());
await dbgClient.connect();
const [,, threadClient] = await attachTestTabAndResume(dbgClient, "test-grips");
await test_object_grip(debuggee, threadClient);
await dbgClient.close();
}
async function test_object_grip(debuggee, threadClient) {
const code = `
stopMe({
method(){
debugger;
},
});
`;
const obj = await eval_and_resume(debuggee, threadClient, code, async frame => {
const arg1 = frame.arguments[0];
Assert.equal(arg1.class, "Object");
await threadClient.pauseGrip(arg1).threadGrip();
return arg1;
});
const objClient = threadClient.pauseGrip(obj);
const method = threadClient.pauseGrip(
(await objClient.getPropertyValue("method")).value.return,
);
// Ensure that we actually paused at the `debugger;` line.
await Promise.all([
wait_for_pause(threadClient, frame => {
Assert.equal(frame.where.line, 4);
Assert.equal(frame.where.column, 8);
}),
method.apply(obj, []),
]);
}
function eval_and_resume(debuggee, threadClient, code, callback) {
return new Promise((resolve, reject) => {
wait_for_pause(threadClient, callback).then(resolve, reject);
// This synchronously blocks until 'threadClient.resume()' above runs
// because the 'paused' event runs everthing in a new event loop.
debuggee.eval(code);
});
}
function wait_for_pause(threadClient, callback = () => {}) {
return new Promise((resolve, reject) => {
threadClient.addOneTimeListener("paused", function(event, packet) {
(async () => {
try {
return await callback(packet.frame);
} finally {
await threadClient.resume();
}
})().then(resolve, reject);
});
});
}

Просмотреть файл

@ -0,0 +1,87 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* eslint-disable no-shadow, max-nested-callbacks */
"use strict";
async function run_test() {
try {
do_test_pending();
await run_test_with_server(DebuggerServer);
// TODO: The server currently doesn't handle request errors
// in workers well, so this test doesn't work with the worker server.
// await run_test_with_server(WorkerDebuggerServer);
} finally {
do_test_finished();
}
}
async function run_test_with_server(server) {
initTestDebuggerServer(server);
const debuggee = addTestGlobal("test-grips", server);
debuggee.eval(`
function stopMe(arg1) {
debugger;
}
`);
const dbgClient = new DebuggerClient(server.connectPipe());
await dbgClient.connect();
const [,, threadClient] = await attachTestTabAndResume(dbgClient, "test-grips");
await test_object_grip(debuggee, threadClient);
await dbgClient.close();
}
async function test_object_grip(debuggee, threadClient) {
const code = `
stopMe({
method: {},
});
`;
const obj = await eval_and_resume(debuggee, threadClient, code, async frame => {
const arg1 = frame.arguments[0];
Assert.equal(arg1.class, "Object");
await threadClient.pauseGrip(arg1).threadGrip();
return arg1;
});
const objClient = threadClient.pauseGrip(obj);
const method = threadClient.pauseGrip(
(await objClient.getPropertyValue("method")).value.return,
);
try {
await method.apply(obj, []);
Assert.ok(false, "expected exception");
} catch (err) {
Assert.equal(err.message, "debugee object is not callable");
}
}
function eval_and_resume(debuggee, threadClient, code, callback) {
return new Promise((resolve, reject) => {
wait_for_pause(threadClient, callback).then(resolve, reject);
// This synchronously blocks until 'threadClient.resume()' above runs
// because the 'paused' event runs everthing in a new event loop.
debuggee.eval(code);
});
}
function wait_for_pause(threadClient, callback = () => {}) {
return new Promise((resolve, reject) => {
threadClient.addOneTimeListener("paused", function(event, packet) {
(async () => {
try {
return await callback(packet.frame);
} finally {
await threadClient.resume();
}
})().then(resolve, reject);
});
});
}

Просмотреть файл

@ -0,0 +1,183 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* eslint-disable no-shadow, max-nested-callbacks */
"use strict";
async function run_test() {
try {
do_test_pending();
await run_test_with_server(DebuggerServer);
await run_test_with_server(WorkerDebuggerServer);
} finally {
do_test_finished();
}
}
async function run_test_with_server(server) {
initTestDebuggerServer(server);
const debuggee = addTestGlobal("test-grips", server);
debuggee.eval(`
function stopMe(arg1) {
debugger;
}
`);
const dbgClient = new DebuggerClient(server.connectPipe());
await dbgClient.connect();
const [,, threadClient] = await attachTestTabAndResume(dbgClient, "test-grips");
await test_object_grip(debuggee, threadClient);
await dbgClient.close();
}
async function test_object_grip(debuggee, threadClient) {
await assert_object_argument(
debuggee,
threadClient,
`
var obj = {
stringProp: "a value",
get stringNormal(){
return "a value";
},
get stringAbrupt() {
throw "a value";
},
get objectNormal() {
return { prop: 4 };
},
get objectAbrupt() {
throw { prop: 4 };
},
get context(){
return this === obj ? "correct context" : "wrong context";
},
method() {
return "a value";
},
};
stopMe(obj);
`,
async objClient => {
const expectedValues = {
stringProp: {
return: "a value",
},
stringNormal: {
return: "a value",
},
stringAbrupt: {
throw: "a value",
},
objectNormal: {
return: {
type: "object",
class: "Object",
ownPropertyLength: 1,
preview: {
kind: "Object",
ownProperties: {
prop: {
value: 4,
},
},
},
},
},
objectAbrupt: {
throw: {
type: "object",
class: "Object",
ownPropertyLength: 1,
preview: {
kind: "Object",
ownProperties: {
prop: {
value: 4,
},
},
},
},
},
context: {
return: "correct context",
},
method: {
return: {
type: "object",
class: "Function",
name: "method",
},
},
};
for (const [key, expected] of Object.entries(expectedValues)) {
const { value } = await objClient.getPropertyValue(key);
assert_completion(value, expected);
}
},
);
}
function assert_object_argument(debuggee, threadClient, code, objectHandler) {
return eval_and_resume(debuggee, threadClient, code, async frame => {
const arg1 = frame.arguments[0];
Assert.equal(arg1.class, "Object");
await objectHandler(threadClient.pauseGrip(arg1));
});
}
function eval_and_resume(debuggee, threadClient, code, callback) {
return new Promise((resolve, reject) => {
wait_for_pause(threadClient, callback).then(resolve, reject);
// This synchronously blocks until 'threadClient.resume()' above runs
// because the 'paused' event runs everthing in a new event loop.
debuggee.eval(code);
});
}
function wait_for_pause(threadClient, callback = () => {}) {
return new Promise((resolve, reject) => {
threadClient.addOneTimeListener("paused", function(event, packet) {
(async () => {
try {
return await callback(packet.frame);
} finally {
await threadClient.resume();
}
})().then(resolve, reject);
});
});
}
function assert_completion(value, expected) {
if (expected && "return" in expected) {
assert_value(value.return, expected.return);
}
if (expected && "throw" in expected) {
assert_value(value.throw, expected.throw);
}
if (!expected) {
assert_value(value, expected);
}
}
function assert_value(actual, expected) {
Assert.equal(typeof actual, typeof expected);
if (typeof expected === "object") {
// Note: We aren't using deepEqual here because we're only doing a cursory
// check of a few properties, not a full comparison of the result, since
// the full outputs includes stuff like preview info that we don't need.
for (const key of Object.keys(expected)) {
assert_value(actual[key], expected[key]);
}
} else {
Assert.equal(actual, expected);
}
}

Просмотреть файл

@ -0,0 +1,84 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* eslint-disable no-shadow, max-nested-callbacks */
"use strict";
async function run_test() {
try {
do_test_pending();
await run_test_with_server(DebuggerServer);
await run_test_with_server(WorkerDebuggerServer);
} finally {
do_test_finished();
}
}
async function run_test_with_server(server) {
initTestDebuggerServer(server);
const debuggee = addTestGlobal("test-grips", server);
debuggee.eval(`
function stopMe(arg1) {
debugger;
}
`);
const dbgClient = new DebuggerClient(server.connectPipe());
await dbgClient.connect();
const [,, threadClient] = await attachTestTabAndResume(dbgClient, "test-grips");
await test_object_grip(debuggee, threadClient);
await dbgClient.close();
}
async function test_object_grip(debuggee, threadClient) {
const code = `
stopMe({
get prop(){
debugger;
},
});
`;
const objClient = await eval_and_resume(debuggee, threadClient, code, async frame => {
const arg1 = frame.arguments[0];
Assert.equal(arg1.class, "Object");
const obj = threadClient.pauseGrip(arg1);
await obj.threadGrip();
return obj;
});
// Ensure that we actually paused at the `debugger;` line.
await Promise.all([
wait_for_pause(threadClient, frame => {
Assert.equal(frame.where.line, 4);
Assert.equal(frame.where.column, 8);
}),
objClient.getPropertyValue("prop"),
]);
}
function eval_and_resume(debuggee, threadClient, code, callback) {
return new Promise((resolve, reject) => {
wait_for_pause(threadClient, callback).then(resolve, reject);
// This synchronously blocks until 'threadClient.resume()' above runs
// because the 'paused' event runs everthing in a new event loop.
debuggee.eval(code);
});
}
function wait_for_pause(threadClient, callback = () => {}) {
return new Promise((resolve, reject) => {
threadClient.addOneTimeListener("paused", function(event, packet) {
(async () => {
try {
return await callback(packet.frame);
} finally {
await threadClient.resume();
}
})().then(resolve, reject);
});
});
}

Просмотреть файл

@ -177,6 +177,11 @@ reason = bug 1104838
[test_objectgrips-21.js]
[test_objectgrips-22.js]
[test_objectgrips-array-like-object.js]
[test_objectgrips-property-value-01.js]
[test_objectgrips-property-value-02.js]
[test_objectgrips-fn-apply-01.js]
[test_objectgrips-fn-apply-02.js]
[test_objectgrips-fn-apply-03.js]
[test_promise_state-01.js]
[test_promise_state-02.js]
[test_promise_state-03.js]

Просмотреть файл

@ -42,6 +42,10 @@ ObjectClient.prototype = {
return this._grip.extensible;
},
threadGrip: DebuggerClient.requester({
type: "threadGrip",
}),
getDefinitionSite: DebuggerClient.requester({
type: "definitionSite"
}, {
@ -181,6 +185,17 @@ ObjectClient.prototype = {
name: arg(0)
}),
/**
* Request the value of the object's specified property.
*
* @param name string The name of the requested property.
* @param onResponse function Called with the request's response.
*/
getPropertyValue: DebuggerClient.requester({
type: "propertyValue",
name: arg(0)
}),
/**
* Request the prototype of the object.
*
@ -190,6 +205,19 @@ ObjectClient.prototype = {
type: "prototype"
}),
/**
* Evaluate a callable object with context and arguments.
*
* @param context any The value to use as the function context.
* @param arguments Array<any> An array of values to use as the function's arguments.
* @param onResponse function Called with the request's response.
*/
apply: DebuggerClient.requester({
type: "apply",
context: arg(0),
arguments: arg(1),
}),
/**
* Request the display string of the object.
*

Просмотреть файл

@ -24,6 +24,11 @@ types.addDictType("object.descriptor", {
set: "nullable:json",
});
types.addDictType("object.completion", {
return: "nullable:json",
throw: "nullable:json"
});
types.addDictType("object.definitionSite", {
source: "source",
line: "number",
@ -45,9 +50,17 @@ types.addDictType("object.property", {
descriptor: "nullable:object.descriptor"
});
types.addDictType("object.propertyValue", {
value: "nullable:object.completion"
});
types.addDictType("object.apply", {
value: "nullable:object.completion"
});
types.addDictType("object.bindings", {
arguments: "array:json",
variables: "json",
variables: "json"
});
types.addDictType("object.scope", {
@ -165,6 +178,19 @@ const objectSpec = generateActorSpec({
},
response: RetVal("object.property")
},
propertyValue: {
request: {
name: Arg(0, "string")
},
response: RetVal("object.propertyValue")
},
apply: {
request: {
context: Arg(0, "nullable:json"),
arguments: Arg(1, "nullable:array:json"),
},
response: RetVal("object.apply")
},
rejectionStack: {
request: {},
response: {

Просмотреть файл

@ -52,10 +52,12 @@ function hasArrayIndex(str) {
*
* {
* state: STATE_NORMAL|STATE_QUOTE|STATE_DQUOTE,
* lastStatement: the last statement in the string
* lastStatement: the last statement in the string,
* isElementAccess: boolean that indicates if the lastStatement has an open
* element access (e.g. `x["match`).
* }
*/
function findCompletionBeginning(str) {
function analyzeInputString(str) {
const bodyStack = [];
let state = STATE_NORMAL;
@ -109,7 +111,7 @@ function findCompletionBeginning(str) {
} else if (OPEN_BODY.includes(c)) {
bodyStack.push({
token: c,
start: start
start
});
start = i + 1;
} else if (CLOSE_BODY.includes(c)) {
@ -164,9 +166,19 @@ function findCompletionBeginning(str) {
}
}
let isElementAccess = false;
if (bodyStack.length === 1 && bodyStack[0].token === "[") {
start = bodyStack[0].start;
isElementAccess = true;
if ([STATE_DQUOTE, STATE_QUOTE, STATE_TEMPLATE_LITERAL].includes(state)) {
state = STATE_NORMAL;
}
}
return {
state: state,
lastStatement: characters.slice(start).join("")
state,
lastStatement: characters.slice(start).join(""),
isElementAccess,
};
}
@ -195,6 +207,8 @@ function findCompletionBeginning(str) {
* matches: Set<string>
* matchProp: Last part of the inputValue that was used to find
* the matches-strings.
* isElementAccess: Boolean set to true if the evaluation is an element
* access (e.g. `window["addEvent`).
* }
*/
function JSPropertyProvider(dbgObject, anEnvironment, inputValue, cursor) {
@ -206,7 +220,12 @@ function JSPropertyProvider(dbgObject, anEnvironment, inputValue, cursor) {
// Analyse the inputValue and find the beginning of the last part that
// should be completed.
const {err, state, lastStatement} = findCompletionBeginning(inputValue);
const {
err,
state,
lastStatement,
isElementAccess
} = analyzeInputString(inputValue);
// There was an error analysing the string.
if (err) {
@ -218,23 +237,24 @@ function JSPropertyProvider(dbgObject, anEnvironment, inputValue, cursor) {
if (state != STATE_NORMAL) {
return null;
}
const completionPart = lastStatement;
const lastDot = completionPart.lastIndexOf(".");
const lastDotIndex = completionPart.lastIndexOf(".");
const lastOpeningBracketIndex = isElementAccess ? completionPart.lastIndexOf("[") : -1;
const lastCompletionCharIndex = Math.max(lastDotIndex, lastOpeningBracketIndex);
const startQuoteRegex = /^('|"|`)/;
// Don't complete on just an empty string.
if (completionPart.trim() == "") {
return null;
}
// Catch literals like [1,2,3] or "foo" and return the matches from
// their prototypes.
// Don't run this is a worker, migrating to acorn should allow this
// to run in a worker - Bug 1217198.
if (!isWorker && lastDot > 0) {
if (!isWorker && lastCompletionCharIndex > 0) {
const parser = new Parser();
parser.logExceptions = false;
const syntaxTree = parser.get(completionPart.slice(0, lastDot));
const syntaxTree = parser.get(completionPart.slice(0, lastCompletionCharIndex));
const lastTree = syntaxTree.getLastSyntaxTree();
const lastBody = lastTree && lastTree.AST.body[lastTree.AST.body.length - 1];
@ -242,19 +262,62 @@ function JSPropertyProvider(dbgObject, anEnvironment, inputValue, cursor) {
// If there were parse errors this won't exist.
if (lastBody) {
const expression = lastBody.expression;
const matchProp = completionPart.slice(lastDot + 1).trimLeft();
const matchProp = completionPart.slice(lastCompletionCharIndex + 1).trimLeft();
let search = matchProp;
let elementAccessQuote;
if (isElementAccess && startQuoteRegex.test(matchProp)) {
elementAccessQuote = matchProp[0];
search = matchProp.replace(startQuoteRegex, "");
}
if (expression.type === "ArrayExpression") {
return getMatchedProps(Array.prototype, matchProp);
} else if (expression.type === "Literal" &&
(typeof expression.value === "string")) {
return getMatchedProps(String.prototype, matchProp);
let arrayProtoProps = getMatchedProps(Array.prototype, search);
if (isElementAccess) {
arrayProtoProps = wrapMatchesInQuotes(arrayProtoProps, elementAccessQuote);
}
return {
isElementAccess,
matchProp,
matches: arrayProtoProps
};
}
if (expression.type === "Literal" && typeof expression.value === "string") {
let stringProtoProps = getMatchedProps(String.prototype, search);
if (isElementAccess) {
stringProtoProps = wrapMatchesInQuotes(stringProtoProps, elementAccessQuote);
}
return {
isElementAccess,
matchProp,
matches: stringProtoProps,
};
}
}
}
// We are completing a variable / a property lookup.
const properties = completionPart.split(".");
const matchProp = properties.pop().trimLeft();
let matchProp;
if (isElementAccess) {
const lastPart = properties[properties.length - 1];
const openBracketIndex = lastPart.lastIndexOf("[");
matchProp = lastPart.substr(openBracketIndex + 1);
properties[properties.length - 1] = lastPart.substring(0, openBracketIndex);
} else {
matchProp = properties.pop().trimLeft();
}
let search = matchProp;
let elementAccessQuote;
if (isElementAccess && startQuoteRegex.test(search)) {
elementAccessQuote = search[0];
search = search.replace(startQuoteRegex, "");
}
let obj = dbgObject;
// The first property must be found in the environment of the paused debugger
@ -262,7 +325,11 @@ function JSPropertyProvider(dbgObject, anEnvironment, inputValue, cursor) {
const env = anEnvironment || obj.asEnvironment();
if (properties.length === 0) {
return getMatchedPropsInEnvironment(env, matchProp);
return {
isElementAccess,
matchProp,
matches: getMatchedPropsInEnvironment(env, search)
};
}
const firstProp = properties.shift().trim();
@ -286,8 +353,8 @@ function JSPropertyProvider(dbgObject, anEnvironment, inputValue, cursor) {
// We get the rest of the properties recursively starting from the
// Debugger.Object that wraps the first property
for (let i = 0; i < properties.length; i++) {
const prop = properties[i].trim();
for (let prop of properties) {
prop = prop.trim();
if (!prop) {
return null;
}
@ -307,10 +374,25 @@ function JSPropertyProvider(dbgObject, anEnvironment, inputValue, cursor) {
// If the final property is a primitive
if (typeof obj != "object") {
return getMatchedProps(obj, matchProp);
return {
isElementAccess,
matchProp,
matches: getMatchedProps(obj, search)
};
}
return getMatchedPropsInDbgObject(obj, matchProp);
let matches = getMatchedPropsInDbgObject(obj, search);
if (isElementAccess) {
// If it's an element access, we need to wrap properties in quotes (either the one
// the user already typed, or `"`).
matches = wrapMatchesInQuotes(matches, elementAccessQuote);
}
return {isElementAccess, matchProp, matches};
}
function wrapMatchesInQuotes(matches, quote = `"`) {
return new Set([...matches].map(p =>
`${quote}${p.replace(new RegExp(`${quote}`, "g"), `\\${quote}`)}${quote}`));
}
/**
@ -423,9 +505,7 @@ function getMatchedProps(obj, match) {
* Object whose properties we want to filter.
* @param {string} match
* Filter for properties that match this string.
* @returns {object} which holds the following properties:
* - {string} matchProp.
* - {Set} matches: List of matched properties.
* @returns {Set} List of matched properties.
*/
function getMatchedPropsImpl(obj, match, {chainIterator, getProperties}) {
const matches = new Set();
@ -460,9 +540,7 @@ function getMatchedPropsImpl(obj, match, {chainIterator, getProperties}) {
if (!propertyMatches(prop)) {
continue;
}
if (prop.indexOf("-") > -1) {
continue;
}
// If it is an array index, we can't take it.
// This uses a trick: converting a string to a number yields NaN if
// the operation failed, and NaN is not equal to itself.
@ -477,10 +555,7 @@ function getMatchedPropsImpl(obj, match, {chainIterator, getProperties}) {
}
}
return {
matchProp: match,
matches,
};
return matches;
}
/**

Просмотреть файл

@ -75,6 +75,16 @@
PRÖP: "",
pröp: "",
}));
window.elementAccessTestCase = Object.create(null, Object.getOwnPropertyDescriptors({
bar: "",
BAR: "",
dataTest: "",
"data-test": "",
'da"ta"test': "",
'da\`ta\`test': "",
"da'ta'test": "",
}));
`;
await state.client.evaluateJSAsync(script);
@ -90,13 +100,18 @@
doAutocompleteDotSurroundedBySpaces,
doAutocompleteAfterOr,
doInsensitiveAutocomplete,
doElementAccessAutocomplete,
];
if (!isWorker) {
// `Cu` is not defined in workers, then we can't test `Cu.Sandbox`
tests.push(doAutocompleteSandbox);
// Array literal completion isn't handled in Workers yet.
tests.push(doAutocompleteArray);
// Array literal, string and commands completion aren't handled in Workers yet.
tests.push(
doAutocompleteArray,
doAutocompleteString,
doAutocompleteCommands,
);
}
for (const test of tests) {
@ -210,6 +225,46 @@
ok(matches.includes("length") && matches.includes("filter"),
"Array autocomplete contains expected results");
ok(!matches.includes("copy"), "Array autocomplete does not contain helpers");
info("test autocomplete for '[1,2,3]['");
matches = (await client.autocomplete("[1,2,3][")).matches;
ok(matches.length > 1);
ok(matches.includes('"length"') && matches.includes('"filter"'),
"Array autocomplete contains expected results, surrounded by quotes");
info("test autocomplete for '[1,2,3]['");
matches = (await client.autocomplete("[1,2,3]['")).matches;
ok(matches.length > 1);
ok(matches.includes("'length'") && matches.includes("'filter'"),
"Array autocomplete contains expected results, surrounded by quotes");
info("test autocomplete for '[1,2,3][l");
matches = (await client.autocomplete("[1,2,3][l")).matches;
ok(matches.length >= 1);
ok(matches.includes('"length"'),
"Array autocomplete contains expected results, surrounded by quotes");
info("test autocomplete for '[1,2,3]['l");
matches = (await client.autocomplete("[1,2,3]['l")).matches;
ok(matches.length >= 1);
ok(matches.includes("'length'"),
"Array autocomplete contains expected results, surrounded by quotes");
}
async function doAutocompleteString(client) {
info(`test autocomplete for "foo".`);
let response = await client.autocomplete(`"foo".`);
let {matches} = response;
ok(matches.length > 0, "There are completion results for the string");
ok(matches.includes("substr") && matches.includes("trim"),
"String autocomplete contains expected results");
info("test autocomplete for `foo`[");
matches = (await client.autocomplete("`foo`[")).matches;
ok(matches.length > 1, "autocomplete string with bracket works");
ok(matches.includes('"substr"') && matches.includes('"trim"'),
"String autocomplete contains expected results, surrounded by quotes");
}
async function doAutocompleteDotSurroundedBySpaces(client) {
@ -287,6 +342,112 @@
matches = (await client.autocomplete("window.insensitiveTestCase.PRÖ")).matches;
is(matches.join("-"), "PRÖP", "expected result with uppercase diacritic");
}
async function doElementAccessAutocomplete(client) {
info("test autocomplete for 'window.elementAccessTestCase['");
let res = (await client.autocomplete("window.elementAccessTestCase["));
is(
res.matches.join("|"),
`"bar"|"da'ta'test"|"da\\"ta\\"test"|"da\`ta\`test"|"data-test"|"dataTest"|"BAR"`,
"autocomplete returns the expected items, wrapped in quotes");
is(res.isElementAccess, true);
info("test autocomplete for 'window.elementAccessTestCase[d'");
res = await client.autocomplete("window.elementAccessTestCase[d");
is(
res.matches.join("|"),
`"da'ta'test"|"da\\"ta\\"test"|"da\`ta\`test"|"data-test"|"dataTest"`,
"autocomplete returns the expected filtered items");
is(res.isElementAccess, true);
info(`test autocomplete for 'window.elementAccessTestCase["d'`);
res = await client.autocomplete(`window.elementAccessTestCase["d`);
is(
res.matches.join("|"),
`"da'ta'test"|"da\\"ta\\"test"|"da\`ta\`test"|"data-test"|"dataTest"`,
"autocomplete returns the expected items, wrapped in quotes");
is(res.isElementAccess, true);
info(`test autocomplete for 'window.elementAccessTestCase["data-`);
res = await client.autocomplete(`window.elementAccessTestCase["data-`);
is(res.matches.join("|"), `"data-test"`,
"autocomplete returns the expected items, wrapped in quotes");
is(res.isElementAccess, true);
info(`test autocomplete for 'window.elementAccessTestCase['d'`);
res = await client.autocomplete(`window.elementAccessTestCase['d`);
is(
res.matches.join("|"),
`'da"ta"test'|'da\\'ta\\'test'|'da\`ta\`test'|'data-test'|'dataTest'`,
"autocomplete returns the expected items, wrapped in the same quotes the user entered");
is(res.isElementAccess, true);
info("test autocomplete for 'window.elementAccessTestCase[`d'");
res = await client.autocomplete("window.elementAccessTestCase[`d");
is(
res.matches.join("|"),
"`da\"ta\"test`|`da'ta'test`|`da\\`ta\\`test`|`data-test`|`dataTest`",
"autocomplete returns the expected items, wrapped in the same quotes the user entered");
is(res.isElementAccess, true);
info(`test autocomplete for '['`);
res = await client.autocomplete(`[`);
is(res.matches.length, 0, "it does not return anything");
is(res.isElementAccess, false);
info(`test autocomplete for '[1,2,3'`);
res = await client.autocomplete(`[1,2,3`);
is(res.matches.length, 0, "it does not return anything");
is(res.isElementAccess, false);
info(`test autocomplete for '["'`);
res = await client.autocomplete(`["`);
is(res.matches.length, 0, "it does not return anything");
is(res.isElementAccess, false);
info(`test autocomplete for '[;'`);
res = await client.autocomplete(`[;`);
is(res.matches.length, 0, "it does not return anything");
is(res.isElementAccess, false);
}
async function doAutocompleteCommands(client) {
info("test autocomplete for 'c'");
let matches = (await client.autocomplete("c")).matches;
ok(matches.includes("cd") && matches.includes("clear"), "commands are returned");
info("test autocomplete for 's'");
matches = (await client.autocomplete("s")).matches;
is(matches.includes("screenshot"), false, "screenshot is not returned");
info("test autocomplete for ':s'");
matches = (await client.autocomplete(":s")).matches;
is(matches.includes(":screenshot"), true, "screenshot is returned");
info("test autocomplete for 'window.c'");
matches = (await client.autocomplete("window.c")).matches;
ok(!matches.includes("cd") && !matches.includes("clear"), "commands are not returned");
info("test autocomplete for 'window[c'");
matches = (await client.autocomplete("window[c")).matches;
ok(!matches.includes("cd") && !matches.includes("clear"), "commands are not returned");
info(`test autocomplete for 'window["c'`);
matches = (await client.autocomplete(`window["c`)).matches;
ok(!matches.includes("cd") && !matches.includes("clear"), "commands are not returned");
info(`test autocomplete for 'window["c'`);
matches = (await client.autocomplete(`window["c`)).matches;
ok(!matches.includes("cd") && !matches.includes("clear"), "commands are not returned");
info(`test autocomplete for 'window[";c'`);
matches = (await client.autocomplete(`window[";c`)).matches;
ok(!matches.includes("cd") && !matches.includes("clear"), "commands are not returned");
info(`test autocomplete for 'window[;c'`);
matches = (await client.autocomplete(`window[;c`)).matches;
ok(!matches.includes("cd") && !matches.includes("clear"), "commands are not returned");
}
</script>
</body>
</html>

Просмотреть файл

@ -2251,7 +2251,6 @@ nsDocShell::SetSecurityUI(nsISecureBrowserUI* aSecurityUI)
MOZ_ASSERT(!mIsBeingDestroyed);
mSecurityUI = aSecurityUI;
mSecurityUI->SetDocShell(this);
return NS_OK;
}

Просмотреть файл

@ -170,7 +170,7 @@ Location::GetURI(nsIURI** aURI, bool aGetInnermostURI)
*aURI = nullptr;
nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
if (!mDocShell) {
if (!docShell) {
return NS_OK;
}

Просмотреть файл

@ -1624,6 +1624,26 @@ nsDOMWindowUtils::GetScrollXYFloat(bool aFlushLayout, float* aScrollX, float* aS
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetVisualViewportOffsetRelativeToLayoutViewport(float* aOffsetX, float* aOffsetY)
{
*aOffsetX = 0;
*aOffsetY = 0;
nsCOMPtr<nsIDocument> doc = GetDocument();
NS_ENSURE_STATE(doc);
nsIPresShell* presShell = doc->GetShell();
NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_AVAILABLE);
nsPoint offset = presShell->GetVisualViewportOffsetRelativeToLayoutViewport();
*aOffsetX = nsPresContext::AppUnitsToFloatCSSPixels(offset.x);
*aOffsetY = nsPresContext::AppUnitsToFloatCSSPixels(offset.y);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetScrollbarSize(bool aFlushLayout, int32_t* aWidth,
int32_t* aHeight)

Просмотреть файл

@ -254,7 +254,7 @@
.createInstance(Ci.nsISecureBrowserUI);
try {
secureUI.setDocShell(docshell);
secureUI.init(docshell);
ok(false, "expected exception passing CPOW to C++");
} catch (e) {
is(e.result, Cr.NS_ERROR_XPC_CANT_PASS_CPOW_TO_NATIVE,

Просмотреть файл

@ -148,7 +148,7 @@ BrowserElementChild.prototype = {
// This is necessary to get security web progress notifications.
var securityUI = Cc['@mozilla.org/secure_browser_ui;1']
.createInstance(Ci.nsISecureBrowserUI);
securityUI.init(content);
securityUI.init(docShell);
// A cache of the menuitem dom objects keyed by the id we generate
// and pass to the embedder

Просмотреть файл

@ -4,6 +4,6 @@
width="640" height="480">
<browser id="browser" type="content" primary="true" flex="1" src="about:blank"
disablehistory="true" disablesecurity="true"/>
disablehistory="true"/>
</window>

Просмотреть файл

@ -844,6 +844,13 @@ interface nsIDOMWindowUtils : nsISupports {
*/
DOMRect getBoundsWithoutFlushing(in Element aElement);
/**
* Returns the offset of the window's visual viewport relative to the
* layout viewport.
*/
void getVisualViewportOffsetRelativeToLayoutViewport(out float aOffsetX,
out float aOffsetY);
const long FLUSH_NONE = -1;
const long FLUSH_STYLE = 0;
const long FLUSH_LAYOUT = 1;

Просмотреть файл

@ -133,7 +133,6 @@ TabParent::LayerToTabParentTable* TabParent::sLayerToTabParentTable = nullptr;
NS_IMPL_ISUPPORTS(TabParent,
nsITabParent,
nsIAuthPromptProvider,
nsISecureBrowserUI,
nsISupportsWeakReference)
TabParent::TabParent(nsIContentParent* aManager,
@ -878,38 +877,6 @@ TabParent::Deactivate()
}
}
NS_IMETHODIMP
TabParent::Init(mozIDOMWindowProxy *window)
{
return NS_OK;
}
NS_IMETHODIMP
TabParent::GetState(uint32_t *aState)
{
NS_ENSURE_ARG(aState);
NS_WARNING("SecurityState not valid here");
*aState = 0;
return NS_OK;
}
NS_IMETHODIMP
TabParent::GetSecInfo(nsITransportSecurityInfo** _result)
{
NS_ENSURE_ARG_POINTER(_result);
NS_WARNING("TransportSecurityInfo not valid here");
*_result = nullptr;
return NS_OK;
}
NS_IMETHODIMP
TabParent::SetDocShell(nsIDocShell *aDocShell)
{
NS_ENSURE_ARG(aDocShell);
NS_WARNING("No mDocShell member in TabParent so there is no docShell to set");
return NS_OK;
}
a11y::PDocAccessibleParent*
TabParent::AllocPDocAccessibleParent(PDocAccessibleParent* aParent,
const uint64_t&, const uint32_t&,

Просмотреть файл

@ -25,7 +25,6 @@
#include "nsIBrowserDOMWindow.h"
#include "nsIDOMEventListener.h"
#include "nsIKeyEventInPluginCallback.h"
#include "nsISecureBrowserUI.h"
#include "nsITabParent.h"
#include "nsIXULBrowserWindow.h"
#include "nsRefreshDriver.h"
@ -83,7 +82,6 @@ class TabParent final : public PBrowserParent
, public nsIDOMEventListener
, public nsITabParent
, public nsIAuthPromptProvider
, public nsISecureBrowserUI
, public nsIKeyEventInPluginCallback
, public nsSupportsWeakReference
, public TabContext
@ -487,7 +485,6 @@ public:
NS_DECL_ISUPPORTS
NS_DECL_NSIAUTHPROMPTPROVIDER
NS_DECL_NSISECUREBROWSERUI
void StartPersistence(uint64_t aOuterWindowID,
nsIWebBrowserPersistDocumentReceiver* aRecv,

Просмотреть файл

@ -684,6 +684,32 @@ ConvertToCdmEncryptionScheme(const GMPEncryptionScheme& aEncryptionScheme)
}
}
static cdm::EncryptionScheme
ConvertToCdmEncryptionScheme(const GMPEncryptionScheme& aEncryptionScheme,
uint64_t aNumCipherBytes)
{
if (aNumCipherBytes == 0) {
// Starting at CDM10, if fed a sample marked as encrypted that has no
// encrypted bytes, the CDM will give a decryption error. So we mark these
// as unencrypted to attempt to avoid such errors -- though ideally our
// demuxers should not emit such data, so log it.
if (aEncryptionScheme != GMPEncryptionScheme::kGMPEncryptionNone) {
GMP_LOG(
"ChromiumCDMChild::ConvertToCdmEncryptionScheme() got scheme marked "
"as encrypted, but with no cipher bytes! This should be caught "
"earlier, preferably by the demuxer! Returning "
"cdm::EncryptionScheme::kUnencrypted");
}
return cdm::EncryptionScheme::kUnencrypted;
}
if (aEncryptionScheme == GMPEncryptionScheme::kGMPEncryptionNone) {
GMP_LOG("ChromiumCDMChild::ConvertToCdmEncryptionScheme() got scheme "
"marked as unecrypted but with > 0 cipher bytes! Something is "
"buggy to emit such data -- likey a demuxer");
}
return ConvertToCdmEncryptionScheme(aEncryptionScheme);
}
static void
InitInputBuffer(const CDMInputBuffer& aBuffer,
nsTArray<cdm::SubsampleEntry>& aSubSamples,
@ -703,15 +729,17 @@ InitInputBuffer(const CDMInputBuffer& aBuffer,
aInputBuffer.iv = aBuffer.mIV().Elements();
aInputBuffer.iv_size = aBuffer.mIV().Length();
uint64_t numCipherBytes = 0;
aSubSamples.SetCapacity(aBuffer.mClearBytes().Length());
for (size_t i = 0; i < aBuffer.mCipherBytes().Length(); i++) {
aSubSamples.AppendElement(cdm::SubsampleEntry{
aBuffer.mClearBytes()[i], aBuffer.mCipherBytes()[i] });
numCipherBytes += aBuffer.mCipherBytes()[i];
}
aInputBuffer.subsamples = aSubSamples.Elements();
aInputBuffer.num_subsamples = aSubSamples.Length();
aInputBuffer.encryption_scheme =
ConvertToCdmEncryptionScheme(aBuffer.mEncryptionScheme());
ConvertToCdmEncryptionScheme(aBuffer.mEncryptionScheme(), numCipherBytes);
}
aInputBuffer.timestamp = aBuffer.mTimestamp();
}

Просмотреть файл

@ -367,18 +367,22 @@ mozilla::ipc::IPCResult
GMPContentChild::RecvPChromiumCDMConstructor(PChromiumCDMChild* aActor)
{
ChromiumCDMChild* child = static_cast<ChromiumCDMChild*>(aActor);
// TODO: Once we support CDM10, create one here, for now try and create CDM9
cdm::Host_9* host9 = child;
cdm::Host_10* host10 = child;
void* cdm = nullptr;
GMPErr err = mGMPChild->GetAPI(CHROMIUM_CDM_API_BACKWARD_COMPAT, host9, &cdm);
GMPErr err = mGMPChild->GetAPI(CHROMIUM_CDM_API, host10, &cdm);
if (err != GMPNoErr || !cdm) {
NS_WARNING("GMPGetAPI call failed trying to get CDM.");
return IPC_FAIL_NO_REASON(this);
// Try to create older version 9 CDM.
cdm::Host_9* host9 = child;
GMPErr err =
mGMPChild->GetAPI(CHROMIUM_CDM_API_BACKWARD_COMPAT, host9, &cdm);
if (err != GMPNoErr || !cdm) {
NS_WARNING("GMPGetAPI call failed trying to get CDM.");
return IPC_FAIL_NO_REASON(this);
}
cdm = new ChromiumCDM9BackwardsCompat(
host10, static_cast<cdm::ContentDecryptionModule_9*>(cdm));
}
cdm::Host_10* host10 = child;
cdm = new ChromiumCDM9BackwardsCompat(
host10, static_cast<cdm::ContentDecryptionModule_9*>(cdm));
child->Init(static_cast<cdm::ContentDecryptionModule_10*>(cdm),
mGMPChild->mStorageId);

Просмотреть файл

@ -15,7 +15,6 @@
#include "nsClassHashtable.h"
#define CHROMIUM_CDM_API_BACKWARD_COMPAT "chromium-cdm9-host4"
// TODO: The following should be used as we switch to cdm10
#define CHROMIUM_CDM_API "chromium-cdm10-host4"
class nsIFile;

Просмотреть файл

@ -81,15 +81,10 @@ protected:
bool SupportsColorDepth(gfx::ColorDepth aColorDepth,
DecoderDoctorDiagnostics* aDiagnostics) const override
{
// We don't support bitDepth > 8 when compositor backend is D3D11.
// But we don't have KnowsCompositor or any object
// that we can ask for the layersbackend type.
// We should remove this restriction until
// we solve the D3D11 compositor backend issue.
#if defined(XP_LINUX) || defined(XP_MACOSX)
return true;
#endif
#if defined(MOZ_WIDGET_ANDROID)
return aColorDepth == gfx::ColorDepth::COLOR_8;
#endif
return true;
}
private:

Просмотреть файл

@ -237,22 +237,6 @@ FFmpegVideoDecoder<LIBAV_VER>::DoDecode(MediaRawData* aSample,
return NS_OK;
}
if ((mCodecContext->pix_fmt == AV_PIX_FMT_YUV420P10LE ||
mCodecContext->pix_fmt == AV_PIX_FMT_YUV444P10LE
#if LIBAVCODEC_VERSION_MAJOR >= 57
|| mCodecContext->pix_fmt == AV_PIX_FMT_YUV444P12LE
#endif
) &&
(!mImageAllocator || (mImageAllocator->GetCompositorBackendType()
!= layers::LayersBackend::LAYERS_BASIC &&
mImageAllocator->GetCompositorBackendType()
!= layers::LayersBackend::LAYERS_OPENGL &&
mImageAllocator->GetCompositorBackendType()
!= layers::LayersBackend::LAYERS_D3D11))) {
return MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
RESULT_DETAIL("unsupported format type (hdr)"));
}
// If we've decoded a frame then we need to output it
int64_t pts = mPtsContext.GuessCorrectPts(mFrame->pkt_pts, mFrame->pkt_dts);
// Retrieve duration from dts.

Просмотреть файл

@ -656,8 +656,14 @@ BufferTextureHost::PushResourceUpdates(wr::TransactionBuilder& aResources,
MOZ_ASSERT(aImageKeys.length() == 3);
const layers::YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
wr::ImageDescriptor yDescriptor(desc.ySize(), desc.yStride(), gfx::SurfaceFormat::A8);
wr::ImageDescriptor cbcrDescriptor(desc.cbCrSize(), desc.cbCrStride(), gfx::SurfaceFormat::A8);
wr::ImageDescriptor yDescriptor(
desc.ySize(),
desc.yStride(),
SurfaceFormatForColorDepth(desc.colorDepth()));
wr::ImageDescriptor cbcrDescriptor(
desc.cbCrSize(),
desc.cbCrStride(),
SurfaceFormatForColorDepth(desc.colorDepth()));
(aResources.*method)(aImageKeys[0], yDescriptor, aExtID, bufferType, 0);
(aResources.*method)(aImageKeys[1], cbcrDescriptor, aExtID, bufferType, 1);
(aResources.*method)(aImageKeys[2], cbcrDescriptor, aExtID, bufferType, 2);
@ -683,6 +689,7 @@ BufferTextureHost::PushDisplayItems(wr::DisplayListBuilder& aBuilder,
aImageKeys[0],
aImageKeys[1],
aImageKeys[2],
wr::ToWrColorDepth(desc.colorDepth()),
wr::ToWrYuvColorSpace(desc.yUVColorSpace()),
aFilter);
}

Просмотреть файл

@ -1164,6 +1164,7 @@ DXGITextureHostD3D11::PushDisplayItems(wr::DisplayListBuilder& aBuilder,
true,
aImageKeys[0],
aImageKeys[1],
wr::ColorDepth::Color8,
wr::ToWrYuvColorSpace(YUVColorSpace::BT601),
aFilter);
break;
@ -1396,6 +1397,7 @@ DXGIYCbCrTextureHostD3D11::PushDisplayItems(wr::DisplayListBuilder& aBuilder,
aImageKeys[0],
aImageKeys[1],
aImageKeys[2],
wr::ToWrColorDepth(mColorDepth),
wr::ToWrYuvColorSpace(mYUVColorSpace),
aFilter);
}

Просмотреть файл

@ -228,10 +228,13 @@ MacIOSurfaceTextureHostOGL::PushDisplayItems(wr::DisplayListBuilder& aBuilder,
case gfx::SurfaceFormat::YUV422: {
MOZ_ASSERT(aImageKeys.length() == 1);
MOZ_ASSERT(mSurface->GetPlaneCount() == 0);
// Those images can only be generated at present by the Apple H264 decoder
// which only supports 8 bits color depth.
aBuilder.PushYCbCrInterleavedImage(aBounds,
aClip,
true,
aImageKeys[0],
wr::ColorDepth::Color8,
wr::ToWrYuvColorSpace(YUVColorSpace::BT601),
aFilter);
break;
@ -239,11 +242,14 @@ MacIOSurfaceTextureHostOGL::PushDisplayItems(wr::DisplayListBuilder& aBuilder,
case gfx::SurfaceFormat::NV12: {
MOZ_ASSERT(aImageKeys.length() == 2);
MOZ_ASSERT(mSurface->GetPlaneCount() == 2);
// Those images can only be generated at present by the Apple H264 decoder
// which only supports 8 bits color depth.
aBuilder.PushNV12Image(aBounds,
aClip,
true,
aImageKeys[0],
aImageKeys[1],
wr::ColorDepth::Color8,
wr::ToWrYuvColorSpace(YUVColorSpace::BT601),
aFilter);
break;

Просмотреть файл

@ -1129,6 +1129,7 @@ DisplayListBuilder::PushYCbCrPlanarImage(const wr::LayoutRect& aBounds,
wr::ImageKey aImageChannel0,
wr::ImageKey aImageChannel1,
wr::ImageKey aImageChannel2,
wr::WrColorDepth aColorDepth,
wr::WrYuvColorSpace aColorSpace,
wr::ImageRendering aRendering)
{
@ -1139,6 +1140,7 @@ DisplayListBuilder::PushYCbCrPlanarImage(const wr::LayoutRect& aBounds,
aImageChannel0,
aImageChannel1,
aImageChannel2,
aColorDepth,
aColorSpace,
aRendering);
}
@ -1149,6 +1151,7 @@ DisplayListBuilder::PushNV12Image(const wr::LayoutRect& aBounds,
bool aIsBackfaceVisible,
wr::ImageKey aImageChannel0,
wr::ImageKey aImageChannel1,
wr::WrColorDepth aColorDepth,
wr::WrYuvColorSpace aColorSpace,
wr::ImageRendering aRendering)
{
@ -1158,6 +1161,7 @@ DisplayListBuilder::PushNV12Image(const wr::LayoutRect& aBounds,
aIsBackfaceVisible,
aImageChannel0,
aImageChannel1,
aColorDepth,
aColorSpace,
aRendering);
}
@ -1167,6 +1171,7 @@ DisplayListBuilder::PushYCbCrInterleavedImage(const wr::LayoutRect& aBounds,
const wr::LayoutRect& aClip,
bool aIsBackfaceVisible,
wr::ImageKey aImageChannel0,
wr::WrColorDepth aColorDepth,
wr::WrYuvColorSpace aColorSpace,
wr::ImageRendering aRendering)
{
@ -1175,6 +1180,7 @@ DisplayListBuilder::PushYCbCrInterleavedImage(const wr::LayoutRect& aBounds,
MergeClipLeaf(aClip),
aIsBackfaceVisible,
aImageChannel0,
aColorDepth,
aColorSpace,
aRendering);
}

Просмотреть файл

@ -408,6 +408,7 @@ public:
wr::ImageKey aImageChannel0,
wr::ImageKey aImageChannel1,
wr::ImageKey aImageChannel2,
wr::WrColorDepth aColorDepth,
wr::WrYuvColorSpace aColorSpace,
wr::ImageRendering aFilter);
@ -416,6 +417,7 @@ public:
bool aIsBackfaceVisible,
wr::ImageKey aImageChannel0,
wr::ImageKey aImageChannel1,
wr::WrColorDepth aColorDepth,
wr::WrYuvColorSpace aColorSpace,
wr::ImageRendering aFilter);
@ -423,6 +425,7 @@ public:
const wr::LayoutRect& aClip,
bool aIsBackfaceVisible,
wr::ImageKey aImageChannel0,
wr::WrColorDepth aColorDepth,
wr::WrYuvColorSpace aColorSpace,
wr::ImageRendering aFilter);

Просмотреть файл

@ -73,6 +73,8 @@ SurfaceFormatToImageFormat(gfx::SurfaceFormat aFormat) {
return Some(wr::ImageFormat::BGRA8);
case gfx::SurfaceFormat::A8:
return Some(wr::ImageFormat::R8);
case gfx::SurfaceFormat::A16:
return Some(wr::ImageFormat::R16);
case gfx::SurfaceFormat::R8G8:
return Some(wr::ImageFormat::RG8);
case gfx::SurfaceFormat::UNKNOWN:
@ -88,6 +90,8 @@ ImageFormatToSurfaceFormat(ImageFormat aFormat) {
return gfx::SurfaceFormat::B8G8R8A8;
case ImageFormat::R8:
return gfx::SurfaceFormat::A8;
case ImageFormat::R16:
return gfx::SurfaceFormat::A16;
default:
return gfx::SurfaceFormat::UNKNOWN;
}
@ -844,6 +848,20 @@ static inline wr::WrYuvColorSpace ToWrYuvColorSpace(YUVColorSpace aYUVColorSpace
return wr::WrYuvColorSpace::Rec601;
}
static inline wr::WrColorDepth ToWrColorDepth(gfx::ColorDepth aColorDepth) {
switch (aColorDepth) {
case gfx::ColorDepth::COLOR_8:
return wr::WrColorDepth::Color8;
case gfx::ColorDepth::COLOR_10:
return wr::WrColorDepth::Color10;
case gfx::ColorDepth::COLOR_12:
return wr::WrColorDepth::Color12;
default:
MOZ_ASSERT_UNREACHABLE("Tried to convert invalid color depth value.");
}
return wr::WrColorDepth::Color8;
}
static inline wr::SyntheticItalics DegreesToSyntheticItalics(float aDegrees) {
wr::SyntheticItalics synthetic_italics;
synthetic_italics.angle = int16_t(std::min(std::max(aDegrees, -89.0f), 89.0f) * 256.0f);

Просмотреть файл

@ -92,6 +92,8 @@ pub type WrFontKey = FontKey;
pub type WrFontInstanceKey = FontInstanceKey;
/// cbindgen:field-names=[mNamespace, mHandle]
type WrYuvColorSpace = YuvColorSpace;
/// cbindgen:field-names=[mNamespace, mHandle]
type WrColorDepth = ColorDepth;
fn make_slice<'a, T>(ptr: *const T, len: usize) -> &'a [T] {
if ptr.is_null() {
@ -2055,6 +2057,7 @@ pub extern "C" fn wr_dp_push_yuv_planar_image(state: &mut WrState,
image_key_0: WrImageKey,
image_key_1: WrImageKey,
image_key_2: WrImageKey,
color_depth: WrColorDepth,
color_space: WrYuvColorSpace,
image_rendering: ImageRendering) {
debug_assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
@ -2066,7 +2069,7 @@ pub extern "C" fn wr_dp_push_yuv_planar_image(state: &mut WrState,
.dl_builder
.push_yuv_image(&prim_info,
YuvData::PlanarYCbCr(image_key_0, image_key_1, image_key_2),
ColorDepth::Color8,
color_depth,
color_space,
image_rendering);
}
@ -2079,6 +2082,7 @@ pub extern "C" fn wr_dp_push_yuv_NV12_image(state: &mut WrState,
is_backface_visible: bool,
image_key_0: WrImageKey,
image_key_1: WrImageKey,
color_depth: WrColorDepth,
color_space: WrYuvColorSpace,
image_rendering: ImageRendering) {
debug_assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
@ -2090,7 +2094,7 @@ pub extern "C" fn wr_dp_push_yuv_NV12_image(state: &mut WrState,
.dl_builder
.push_yuv_image(&prim_info,
YuvData::NV12(image_key_0, image_key_1),
ColorDepth::Color8,
color_depth,
color_space,
image_rendering);
}
@ -2102,6 +2106,7 @@ pub extern "C" fn wr_dp_push_yuv_interleaved_image(state: &mut WrState,
clip: LayoutRect,
is_backface_visible: bool,
image_key_0: WrImageKey,
color_depth: WrColorDepth,
color_space: WrYuvColorSpace,
image_rendering: ImageRendering) {
debug_assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
@ -2113,7 +2118,7 @@ pub extern "C" fn wr_dp_push_yuv_interleaved_image(state: &mut WrState,
.dl_builder
.push_yuv_image(&prim_info,
YuvData::InterleavedYCbCr(image_key_0),
ColorDepth::Color8,
color_depth,
color_space,
image_rendering);
}

Просмотреть файл

@ -69,6 +69,18 @@ enum class ClipMode {
Sentinel /* this must be last for serialization purposes. */
};
// Specifies the color depth of an image. Currently only used for YUV images.
enum class ColorDepth : uint8_t {
// 8 bits image (most common)
Color8,
// 10 bits image
Color10,
// 12 bits image
Color12,
Sentinel /* this must be last for serialization purposes. */
};
enum class ExtendMode : uint32_t {
Clamp,
Repeat,
@ -942,6 +954,8 @@ struct GlyphOptions {
}
};
using WrColorDepth = ColorDepth;
using WrYuvColorSpace = YuvColorSpace;
struct ByteSlice {
@ -1499,6 +1513,7 @@ void wr_dp_push_yuv_NV12_image(WrState *aState,
bool aIsBackfaceVisible,
WrImageKey aImageKey0,
WrImageKey aImageKey1,
WrColorDepth aColorDepth,
WrYuvColorSpace aColorSpace,
ImageRendering aImageRendering)
WR_FUNC;
@ -1510,6 +1525,7 @@ void wr_dp_push_yuv_interleaved_image(WrState *aState,
LayoutRect aClip,
bool aIsBackfaceVisible,
WrImageKey aImageKey0,
WrColorDepth aColorDepth,
WrYuvColorSpace aColorSpace,
ImageRendering aImageRendering)
WR_FUNC;
@ -1523,6 +1539,7 @@ void wr_dp_push_yuv_planar_image(WrState *aState,
WrImageKey aImageKey0,
WrImageKey aImageKey1,
WrImageKey aImageKey2,
WrColorDepth aColorDepth,
WrYuvColorSpace aColorSpace,
ImageRendering aImageRendering)
WR_FUNC;

Просмотреть файл

@ -36,8 +36,9 @@ class BitArray
void clear(bool value) {
memset(map, value ? 0xFF : 0, sizeof(map));
if (value)
if (value) {
map[numSlots - 1] &= paddingMask;
}
}
inline bool get(size_t offset) const {
@ -63,8 +64,9 @@ class BitArray
bool isAllClear() const {
for (size_t i = 0; i < numSlots; i++) {
if (map[i])
if (map[i]) {
return false;
}
}
return true;
}

Просмотреть файл

@ -12,16 +12,18 @@ using namespace js;
SparseBitmap::~SparseBitmap()
{
for (Data::Range r(data.all()); !r.empty(); r.popFront())
for (Data::Range r(data.all()); !r.empty(); r.popFront()) {
js_delete(r.front().value());
}
}
size_t
SparseBitmap::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
{
size_t size = data.shallowSizeOfExcludingThis(mallocSizeOf);
for (Data::Range r(data.all()); !r.empty(); r.popFront())
for (Data::Range r(data.all()); !r.empty(); r.popFront()) {
size += mallocSizeOf(r.front().value());
}
return size;
}
@ -30,8 +32,9 @@ SparseBitmap::createBlock(Data::AddPtr p, size_t blockId, AutoEnterOOMUnsafeRegi
{
MOZ_ASSERT(!p);
BitBlock* block = js_new<BitBlock>();
if (!block || !data.add(p, blockId, block))
if (!block || !data.add(p, blockId, block)) {
oomUnsafe.crash("Bitmap OOM");
}
std::fill(block->begin(), block->end(), 0);
return *block;
}
@ -43,8 +46,9 @@ SparseBitmap::getBit(size_t bit) const
size_t blockWord = blockStartWord(word);
BitBlock* block = getBlock(blockWord / WordsInBlock);
if (block)
if (block) {
return (*block)[word - blockWord] & (uintptr_t(1) << (bit % JS_BITS_PER_WORD));
}
return false;
}
@ -73,8 +77,9 @@ SparseBitmap::bitwiseOrWith(const SparseBitmap& other)
for (Data::Range r(other.data.all()); !r.empty(); r.popFront()) {
const BitBlock& otherBlock = *r.front().value();
BitBlock& block = getOrCreateBlock(r.front().key());
for (size_t i = 0; i < WordsInBlock; i++)
for (size_t i = 0; i < WordsInBlock; i++) {
block[i] |= otherBlock[i];
}
}
}
@ -87,11 +92,13 @@ SparseBitmap::bitwiseOrInto(DenseBitmap& other) const
size_t numWords = wordIntersectCount(blockWord, other);
#ifdef DEBUG
// Any words out of range in other should be zero in this bitmap.
for (size_t i = numWords; i < WordsInBlock; i++)
for (size_t i = numWords; i < WordsInBlock; i++) {
MOZ_ASSERT(!block[i]);
}
#endif
for (size_t i = 0; i < numWords; i++)
for (size_t i = 0; i < numWords; i++) {
other.word(blockWord + i) |= block[i];
}
}
}
@ -105,7 +112,8 @@ SparseBitmap::bitwiseOrRangeInto(size_t wordStart, size_t numWords, uintptr_t* t
BitBlock* block = getBlock(blockWord / WordsInBlock);
if (block) {
for (size_t i = 0; i < numWords; i++)
for (size_t i = 0; i < numWords; i++) {
target[i] |= (*block)[wordStart - blockWord + i];
}
}
}

Просмотреть файл

@ -59,8 +59,9 @@ class DenseBitmap
}
void bitwiseOrRangeInto(size_t wordStart, size_t numWords, uintptr_t* target) const {
for (size_t i = 0; i < numWords; i++)
for (size_t i = 0; i < numWords; i++) {
target[i] |= data[wordStart + i];
}
}
};
@ -100,8 +101,9 @@ class SparseBitmap
// the add() within createBlock().
AutoEnterOOMUnsafeRegion oomUnsafe;
Data::AddPtr p = data.lookupForAdd(blockId);
if (p)
if (p) {
return *p->value();
}
return createBlock(p, blockId, oomUnsafe);
}

Просмотреть файл

@ -124,8 +124,9 @@ class Fifo
// |const T&| or a |T&&|.
template <typename U>
MOZ_MUST_USE bool pushBack(U&& u) {
if (!rear_.append(std::forward<U>(u)))
if (!rear_.append(std::forward<U>(u))) {
return false;
}
fixup();
return true;
}
@ -133,8 +134,9 @@ class Fifo
// Construct a T in-place at the back of the queue.
template <typename... Args>
MOZ_MUST_USE bool emplaceBack(Args&&... args) {
if (!rear_.emplaceBack(std::forward<Args>(args)...))
if (!rear_.emplaceBack(std::forward<Args>(args)...)) {
return false;
}
fixup();
return true;
}

Просмотреть файл

@ -75,8 +75,9 @@ class InlineTable : private AllocPolicy
InlineEntry* end = inlineEnd();
for (InlineEntry* it = inlineStart(); it != end; ++it) {
if (it->key && !it->moveTo(table_))
if (it->key && !it->moveTo(table_)) {
return false;
}
}
inlNext_ = InlineEntries + 1;
@ -87,8 +88,9 @@ class InlineTable : private AllocPolicy
MOZ_NEVER_INLINE
MOZ_MUST_USE bool switchAndAdd(const InlineEntry& entry) {
if (!switchToTable())
if (!switchToTable()) {
return false;
}
return entry.putNew(table_);
}
@ -148,10 +150,12 @@ class InlineTable : private AllocPolicy
bool operator==(const Ptr& other) const {
MOZ_ASSERT(found() && other.found());
if (isInlinePtr_ != other.isInlinePtr_)
if (isInlinePtr_ != other.isInlinePtr_) {
return false;
if (isInlinePtr_)
}
if (isInlinePtr_) {
return inlPtr_ == other.inlPtr_;
}
return tablePtr_ == other.tablePtr_;
}
@ -208,10 +212,12 @@ class InlineTable : private AllocPolicy
bool operator==(const AddPtr& other) const {
MOZ_ASSERT(found() && other.found());
if (isInlinePtr_ != other.isInlinePtr_)
if (isInlinePtr_ != other.isInlinePtr_) {
return false;
if (isInlinePtr_)
}
if (isInlinePtr_) {
return inlAddPtr_ == other.inlAddPtr_;
}
return tableAddPtr_ == other.tableAddPtr_;
}
@ -247,13 +253,15 @@ class InlineTable : private AllocPolicy
Ptr lookup(const Lookup& l) {
MOZ_ASSERT(keyNonZero(l));
if (usingTable())
if (usingTable()) {
return Ptr(table_.lookup(l));
}
InlineEntry* end = inlineEnd();
for (InlineEntry* it = inlineStart(); it != end; ++it) {
if (it->key && HashPolicy::match(it->key, l))
if (it->key && HashPolicy::match(it->key, l)) {
return Ptr(it);
}
}
return Ptr(nullptr);
@ -263,13 +271,15 @@ class InlineTable : private AllocPolicy
AddPtr lookupForAdd(const Lookup& l) {
MOZ_ASSERT(keyNonZero(l));
if (usingTable())
if (usingTable()) {
return AddPtr(table_.lookupForAdd(l));
}
InlineEntry* end = inlineEnd();
for (InlineEntry* it = inlineStart(); it != end; ++it) {
if (it->key && HashPolicy::match(it->key, l))
if (it->key && HashPolicy::match(it->key, l)) {
return AddPtr(it, true);
}
}
// The add pointer that's returned here may indicate the limit entry of
@ -291,8 +301,9 @@ class InlineTable : private AllocPolicy
// Switching to table mode before we add this pointer.
if (addPtr == inlineStart() + InlineEntries) {
if (!switchToTable())
if (!switchToTable()) {
return false;
}
return table_.putNew(std::forward<KeyInput>(key),
std::forward<Args>(args)...);
}
@ -300,8 +311,9 @@ class InlineTable : private AllocPolicy
MOZ_ASSERT(!p.found());
MOZ_ASSERT(uintptr_t(inlineEnd()) == uintptr_t(p.inlAddPtr_));
if (!this->checkSimulatedOOM())
if (!this->checkSimulatedOOM()) {
return false;
}
addPtr->update(std::forward<KeyInput>(key),
std::forward<Args>(args)...);
@ -329,8 +341,9 @@ class InlineTable : private AllocPolicy
}
void remove(const Lookup& l) {
if (Ptr p = lookup(l))
if (Ptr p = lookup(l)) {
remove(p);
}
}
class Range
@ -375,8 +388,9 @@ class InlineTable : private AllocPolicy
void advancePastNulls(InlineEntry* begin) {
InlineEntry* newCur = begin;
while (newCur < end_ && nullptr == newCur->key)
while (newCur < end_ && nullptr == newCur->key) {
++newCur;
}
MOZ_ASSERT(uintptr_t(newCur) <= uintptr_t(end_));
cur_ = newCur;
}
@ -393,17 +407,19 @@ class InlineTable : private AllocPolicy
Entry front() {
MOZ_ASSERT(!empty());
if (isInlineRange())
if (isInlineRange()) {
return Entry(cur_);
}
return Entry(&tableRange_->front());
}
void popFront() {
MOZ_ASSERT(!empty());
if (isInlineRange())
if (isInlineRange()) {
bumpCurPtr();
else
} else {
tableRange_->popFront();
}
}
};
@ -467,15 +483,17 @@ class InlineMap
const Key& key() const {
MOZ_ASSERT(!!mapEntry_ != !!inlineEntry_);
if (mapEntry_)
if (mapEntry_) {
return mapEntry_->key();
}
return inlineEntry_->key;
}
Value& value() {
MOZ_ASSERT(!!mapEntry_ != !!inlineEntry_);
if (mapEntry_)
if (mapEntry_) {
return mapEntry_->value();
}
return inlineEntry_->value;
}
};
@ -605,8 +623,9 @@ class InlineSet
operator T() const {
MOZ_ASSERT(!!setEntry_ != !!inlineEntry_);
if (setEntry_)
if (setEntry_) {
return *setEntry_;
}
return inlineEntry_->key;
}
};

Просмотреть файл

@ -30,8 +30,9 @@ BumpChunk::newWithCapacity(size_t size)
MOZ_DIAGNOSTIC_ASSERT(RoundUpPow2(size) == size);
MOZ_DIAGNOSTIC_ASSERT(size >= sizeof(BumpChunk));
void* mem = js_malloc(size);
if (!mem)
if (!mem) {
return nullptr;
}
UniquePtr<BumpChunk> result(new (mem) BumpChunk(size));
@ -110,10 +111,12 @@ LifoAlloc::reset(size_t defaultChunkSize)
{
MOZ_ASSERT(mozilla::IsPowerOfTwo(defaultChunkSize));
while (!chunks_.empty())
while (!chunks_.empty()) {
chunks_.popFirst();
while (!unused_.empty())
}
while (!unused_.empty()) {
unused_.popFirst();
}
defaultChunkSize_ = defaultChunkSize;
markCount = 0;
curSize_ = 0;
@ -157,8 +160,9 @@ LifoAlloc::newChunkWithCapacity(size_t n)
// Create a new BumpChunk, and allocate space for it.
UniqueBumpChunk result = detail::BumpChunk::newWithCapacity(chunkSize);
if (!result)
if (!result) {
return nullptr;
}
MOZ_ASSERT(result->computedSizeOfIncludingThis() == chunkSize);
return result;
}
@ -190,8 +194,9 @@ LifoAlloc::getOrCreateChunk(size_t n)
// Allocate a new BumpChunk with enough space for the next allocation.
UniqueBumpChunk newChunk = newChunkWithCapacity(n);
if (!newChunk)
if (!newChunk) {
return false;
}
size_t size = newChunk->computedSizeOfIncludingThis();
chunks_.append(std::move(newChunk));
incrementCurSize(size);
@ -216,8 +221,9 @@ LifoAlloc::transferUnusedFrom(LifoAlloc* other)
MOZ_ASSERT(!markCount);
size_t size = 0;
for (detail::BumpChunk& bc : other->unused_)
for (detail::BumpChunk& bc : other->unused_) {
size += bc.computedSizeOfIncludingThis();
}
appendUnused(std::move(other->unused_));
incrementCurSize(size);

Просмотреть файл

@ -153,8 +153,9 @@ class SingleLinkedList
}
void pushFront(UniquePtr<T, D>&& elem) {
if (!last_)
if (!last_) {
last_ = elem.get();
}
elem->next_ = std::move(head_);
head_ = std::move(elem);
assertInvariants();
@ -171,12 +172,14 @@ class SingleLinkedList
assertInvariants();
}
void appendAll(SingleLinkedList&& list) {
if (list.empty())
if (list.empty()) {
return;
if (last_)
}
if (last_) {
last_->next_ = std::move(list.head_);
else
} else {
head_ = std::move(list.head_);
}
last_ = list.last_;
list.last_ = nullptr;
assertInvariants();
@ -186,8 +189,9 @@ class SingleLinkedList
MOZ_ASSERT(head_);
UniquePtr<T, D> result = std::move(head_);
head_ = std::move(result->next_);
if (!head_)
if (!head_) {
last_ = nullptr;
}
assertInvariants();
return result;
}
@ -443,8 +447,9 @@ class BumpChunk : public SingleLinkedListElement<BumpChunk>
// Space remaining in the current chunk.
size_t unused() const {
uint8_t* aligned = nextAllocBase(end());
if (aligned < capacity_)
if (aligned < capacity_) {
return capacity_ - aligned;
}
return 0;
}
@ -454,12 +459,14 @@ class BumpChunk : public SingleLinkedListElement<BumpChunk>
uint8_t* aligned = nextAllocBase(end());
uint8_t* newBump = nextAllocEnd(aligned, n);
if (newBump > capacity_)
if (newBump > capacity_) {
return nullptr;
}
// Check for overflow.
if (MOZ_UNLIKELY(newBump < bump_))
if (MOZ_UNLIKELY(newBump < bump_)) {
return nullptr;
}
MOZ_ASSERT(canAlloc(n)); // Ensure consistency between "can" and "try".
setBump(newBump);
@ -552,8 +559,9 @@ class LifoAlloc
// Append unused chunks to the end of this LifoAlloc.
void appendUnused(BumpChunkList&& otherUnused) {
#ifdef DEBUG
for (detail::BumpChunk& bc: otherUnused)
for (detail::BumpChunk& bc: otherUnused) {
MOZ_ASSERT(bc.empty());
}
#endif
unused_.appendAll(std::move(otherUnused));
}
@ -567,8 +575,9 @@ class LifoAlloc
// Track the amount of space allocated in used and unused chunks.
void incrementCurSize(size_t size) {
curSize_ += size;
if (curSize_ > peakSize_)
if (curSize_ > peakSize_) {
peakSize_ = curSize_;
}
}
void decrementCurSize(size_t size) {
MOZ_ASSERT(curSize_ >= size);
@ -578,11 +587,13 @@ class LifoAlloc
MOZ_ALWAYS_INLINE
void* allocImpl(size_t n) {
void* result;
if (!chunks_.empty() && (result = chunks_.last()->tryAlloc(n)))
if (!chunks_.empty() && (result = chunks_.last()->tryAlloc(n))) {
return result;
}
if (!getOrCreateChunk(n))
if (!getOrCreateChunk(n)) {
return nullptr;
}
// Since we just created a large enough chunk, this can't fail.
result = chunks_.last()->tryAlloc(n);
@ -636,8 +647,9 @@ class LifoAlloc
static const unsigned HUGE_ALLOCATION = 50 * 1024 * 1024;
void freeAllIfHugeAndUnused() {
if (markCount == 0 && curSize_ > HUGE_ALLOCATION)
if (markCount == 0 && curSize_ > HUGE_ALLOCATION) {
freeAll();
}
}
MOZ_ALWAYS_INLINE
@ -645,8 +657,9 @@ class LifoAlloc
#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
// Only simulate OOMs when we are not using the LifoAlloc as an
// infallible allocator.
if (fallibleScope_)
if (fallibleScope_) {
JS_OOM_POSSIBLY_FAIL();
}
#endif
return allocImpl(n);
}
@ -659,8 +672,9 @@ class LifoAlloc
static_assert(alignof(T) <= detail::LIFO_ALLOC_ALIGN,
"LifoAlloc must provide enough alignment to store T");
void* ptr = alloc(n);
if (!ptr)
if (!ptr) {
return nullptr;
}
return new (ptr) T(std::forward<Args>(args)...);
}
@ -668,8 +682,9 @@ class LifoAlloc
MOZ_ALWAYS_INLINE
void* allocInfallible(size_t n) {
AutoEnterOOMUnsafeRegion oomUnsafe;
if (void* result = allocImpl(n))
if (void* result = allocImpl(n)) {
return result;
}
oomUnsafe.crash("LifoAlloc::allocInfallible");
return nullptr;
}
@ -683,19 +698,22 @@ class LifoAlloc
size_t total = 0;
if (!chunks_.empty()) {
total += chunks_.last()->unused();
if (total >= n)
if (total >= n) {
return true;
}
}
for (detail::BumpChunk& bc : unused_) {
total += bc.unused();
if (total >= n)
if (total >= n) {
return true;
}
}
UniqueBumpChunk newChunk = newChunkWithCapacity(n);
if (!newChunk)
if (!newChunk) {
return false;
}
size_t size = newChunk->computedSizeOfIncludingThis();
unused_.pushFront(std::move(newChunk));
incrementCurSize(size);
@ -745,8 +763,9 @@ class LifoAlloc
template <typename T>
T* newArrayUninitialized(size_t count) {
size_t bytes;
if (MOZ_UNLIKELY(!CalculateAllocSize<T>(count, &bytes)))
if (MOZ_UNLIKELY(!CalculateAllocSize<T>(count, &bytes))) {
return nullptr;
}
return static_cast<T*>(alloc(bytes));
}
@ -754,8 +773,9 @@ class LifoAlloc
Mark mark() {
markCount++;
if (chunks_.empty())
if (chunks_.empty()) {
return Mark();
}
return chunks_.last()->mark();
}
@ -764,41 +784,49 @@ class LifoAlloc
// Move the blocks which are after the mark to the set of unused chunks.
BumpChunkList released;
if (!mark.markedChunk())
if (!mark.markedChunk()) {
released = std::move(chunks_);
else
} else {
released = chunks_.splitAfter(mark.markedChunk());
}
// Release the content of all the blocks which are after the marks.
for (detail::BumpChunk& bc : released)
for (detail::BumpChunk& bc : released) {
bc.release();
}
unused_.appendAll(std::move(released));
// Release everything which follows the mark in the last chunk.
if (!chunks_.empty())
if (!chunks_.empty()) {
chunks_.last()->release(mark);
}
}
void releaseAll() {
MOZ_ASSERT(!markCount);
for (detail::BumpChunk& bc : chunks_)
for (detail::BumpChunk& bc : chunks_) {
bc.release();
}
unused_.appendAll(std::move(chunks_));
}
// Protect the content of the LifoAlloc chunks.
#ifdef LIFO_CHUNK_PROTECT
void setReadOnly() {
for (detail::BumpChunk& bc : chunks_)
for (detail::BumpChunk& bc : chunks_) {
bc.setReadOnly();
for (detail::BumpChunk& bc : unused_)
}
for (detail::BumpChunk& bc : unused_) {
bc.setReadOnly();
}
}
void setReadWrite() {
for (detail::BumpChunk& bc : chunks_)
for (detail::BumpChunk& bc : chunks_) {
bc.setReadWrite();
for (detail::BumpChunk& bc : unused_)
}
for (detail::BumpChunk& bc : unused_) {
bc.setReadWrite();
}
}
#else
void setReadOnly() const {}
@ -808,8 +836,9 @@ class LifoAlloc
// Get the total "used" (occupied bytes) count for the arena chunks.
size_t used() const {
size_t accum = 0;
for (const detail::BumpChunk& chunk : chunks_)
for (const detail::BumpChunk& chunk : chunks_) {
accum += chunk.used();
}
return accum;
}
@ -822,28 +851,33 @@ class LifoAlloc
// Return the number of bytes remaining to allocate in the current chunk.
// e.g. How many bytes we can allocate before needing a new block.
size_t availableInCurrentChunk() const {
if (chunks_.empty())
if (chunks_.empty()) {
return 0;
}
return chunks_.last()->unused();
}
// Get the total size of the arena chunks (including unused space).
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
size_t n = 0;
for (const detail::BumpChunk& chunk : chunks_)
for (const detail::BumpChunk& chunk : chunks_) {
n += chunk.sizeOfIncludingThis(mallocSizeOf);
for (const detail::BumpChunk& chunk : unused_)
}
for (const detail::BumpChunk& chunk : unused_) {
n += chunk.sizeOfIncludingThis(mallocSizeOf);
}
return n;
}
// Get the total size of the arena chunks (including unused space).
size_t computedSizeOfExcludingThis() const {
size_t n = 0;
for (const detail::BumpChunk& chunk : chunks_)
for (const detail::BumpChunk& chunk : chunks_) {
n += chunk.computedSizeOfIncludingThis();
for (const detail::BumpChunk& chunk : unused_)
}
for (const detail::BumpChunk& chunk : unused_) {
n += chunk.computedSizeOfIncludingThis();
}
return n;
}
@ -869,8 +903,9 @@ class LifoAlloc
#ifdef DEBUG
bool contains(void* ptr) const {
for (const detail::BumpChunk& chunk : chunks_) {
if (chunk.contains(ptr))
if (chunk.contains(ptr)) {
return true;
}
}
return false;
}
@ -912,8 +947,9 @@ class LifoAlloc
chunkEnd_(alloc.chunks_.end()),
head_(nullptr)
{
if (chunkIt_ != chunkEnd_)
if (chunkIt_ != chunkEnd_) {
head_ = chunkIt_->begin();
}
}
// Return true if there are no more bytes to enumerate.
@ -957,8 +993,9 @@ class MOZ_NON_TEMPORARY_CLASS LifoAllocScope
}
~LifoAllocScope() {
if (shouldRelease)
if (shouldRelease) {
lifoAlloc->release(mark);
}
}
LifoAlloc& alloc() {
@ -989,24 +1026,27 @@ class LifoAllocPolicy
template <typename T>
T* maybe_pod_malloc(size_t numElems) {
size_t bytes;
if (MOZ_UNLIKELY(!CalculateAllocSize<T>(numElems, &bytes)))
if (MOZ_UNLIKELY(!CalculateAllocSize<T>(numElems, &bytes))) {
return nullptr;
}
void* p = fb == Fallible ? alloc_.alloc(bytes) : alloc_.allocInfallible(bytes);
return static_cast<T*>(p);
}
template <typename T>
T* maybe_pod_calloc(size_t numElems) {
T* p = maybe_pod_malloc<T>(numElems);
if (MOZ_UNLIKELY(!p))
if (MOZ_UNLIKELY(!p)) {
return nullptr;
}
memset(p, 0, numElems * sizeof(T));
return p;
}
template <typename T>
T* maybe_pod_realloc(T* p, size_t oldSize, size_t newSize) {
T* n = maybe_pod_malloc<T>(newSize);
if (MOZ_UNLIKELY(!n))
if (MOZ_UNLIKELY(!n)) {
return nullptr;
}
MOZ_ASSERT(!(oldSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value));
memcpy(n, p, Min(oldSize * sizeof(T), newSize * sizeof(T)));
return n;

Просмотреть файл

@ -56,10 +56,12 @@ class ProtectedRegionTree
// included in a range, or if an address is already registered as a
// protected region.
static int compare(const Region& A, const Region& B) {
if (A.last < B.first)
if (A.last < B.first) {
return -1;
if (A.first > B.last)
}
if (A.first > B.last) {
return 1;
}
return 0;
}
};
@ -87,8 +89,9 @@ class ProtectedRegionTree
MOZ_ASSERT(addr && size);
LockGuard<Mutex> guard(lock);
AutoEnterOOMUnsafeRegion oomUnsafe;
if (!tree.insert(Region(addr, size)))
if (!tree.insert(Region(addr, size))) {
oomUnsafe.crash("Failed to store allocation ID.");
}
}
void remove(uintptr_t addr) {
@ -98,8 +101,9 @@ class ProtectedRegionTree
}
bool isProtected(uintptr_t addr) {
if (!addr)
if (!addr) {
return false;
}
LockGuard<Mutex> guard(lock);
return tree.maybeLookup(Region(addr, 1));
}
@ -131,15 +135,17 @@ MemoryProtectionExceptionHandler::isDisabled()
void
MemoryProtectionExceptionHandler::addRegion(void* addr, size_t size)
{
if (sExceptionHandlerInstalled && sProtectedRegionsInit)
if (sExceptionHandlerInstalled && sProtectedRegionsInit) {
sProtectedRegions.insert(uintptr_t(addr), size);
}
}
void
MemoryProtectionExceptionHandler::removeRegion(void* addr)
{
if (sExceptionHandlerInstalled && sProtectedRegionsInit)
if (sExceptionHandlerInstalled && sProtectedRegionsInit) {
sProtectedRegions.remove(uintptr_t(addr));
}
}
/* -------------------------------------------------------------------------- */
@ -216,8 +222,9 @@ MemoryProtectionExceptionHandler::install()
MOZ_ASSERT(!sExceptionHandlerInstalled);
// If the exception handler is disabled, report success anyway.
if (MemoryProtectionExceptionHandler::isDisabled())
if (MemoryProtectionExceptionHandler::isDisabled()) {
return true;
}
// Install our new exception handler.
sVectoredExceptionHandler = AddVectoredExceptionHandler(/* FirstHandler = */ true,
@ -277,12 +284,13 @@ UnixExceptionHandler(int signum, siginfo_t* info, void* context)
// Forward to the previous handler which may be a debugger,
// the crash reporter or something else entirely.
if (sPrevSEGVHandler.sa_flags & SA_SIGINFO)
if (sPrevSEGVHandler.sa_flags & SA_SIGINFO) {
sPrevSEGVHandler.sa_sigaction(signum, info, context);
else if (sPrevSEGVHandler.sa_handler == SIG_DFL || sPrevSEGVHandler.sa_handler == SIG_IGN)
} else if (sPrevSEGVHandler.sa_handler == SIG_DFL || sPrevSEGVHandler.sa_handler == SIG_IGN) {
sigaction(SIGSEGV, &sPrevSEGVHandler, nullptr);
else
} else {
sPrevSEGVHandler.sa_handler(signum);
}
// If we reach here, we're returning to let the default signal handler deal
// with the exception. This is technically undefined behavior, but
@ -295,8 +303,9 @@ MemoryProtectionExceptionHandler::install()
MOZ_ASSERT(!sExceptionHandlerInstalled);
// If the exception handler is disabled, report success anyway.
if (MemoryProtectionExceptionHandler::isDisabled())
if (MemoryProtectionExceptionHandler::isDisabled()) {
return true;
}
// Install our new exception handler and save the previous one.
struct sigaction faultHandler = {};
@ -571,21 +580,25 @@ MachExceptionHandler()
previous.behavior, previous.flavor);
// If we failed even receiving the message, just give up.
if (ret != MACH_MSG_SUCCESS)
if (ret != MACH_MSG_SUCCESS) {
MOZ_CRASH("MachExceptionHandler: mach_msg failed to receive a message!");
}
// Terminate the thread if we're shutting down.
if (request.header.msgh_id == sIDQuit)
if (request.header.msgh_id == sIDQuit) {
return;
}
// The only other valid message ID is the one associated with the
// EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES behavior we chose.
if (request.header.msgh_id != sIDRequest64)
if (request.header.msgh_id != sIDRequest64) {
MOZ_CRASH("MachExceptionHandler: Unexpected Message ID!");
}
// Make sure we can understand the exception we received.
if (request.exception != EXC_BAD_ACCESS || request.code_count != 2)
if (request.exception != EXC_BAD_ACCESS || request.code_count != 2) {
MOZ_CRASH("MachExceptionHandler: Unexpected exception type!");
}
// Get the address that the offending code tried to access.
uintptr_t address = uintptr_t(request.code[1]);
@ -606,8 +619,9 @@ MachExceptionHandler()
// If the previous handler requested thread state, get it here.
stateCount = THREAD_STATE_MAX;
ret = thread_get_state(request.thread.name, previous.flavor, state, &stateCount);
if (ret != KERN_SUCCESS)
if (ret != KERN_SUCCESS) {
MOZ_CRASH("MachExceptionHandler: Could not get the thread state to forward!");
}
}
// Depending on the behavior of the previous handler, the forwarded
@ -653,8 +667,9 @@ MachExceptionHandler()
forward.header.msgh_remote_port = previous.port;
ret = mach_msg(&forward.header, MACH_SEND_MSG, forward.header.msgh_size, 0,
MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
if (ret != MACH_MSG_SUCCESS)
if (ret != MACH_MSG_SUCCESS) {
MOZ_CRASH("MachExceptionHandler: Failed to forward to the previous handler!");
}
} else {
// There was no previous task-level exception handler, so defer to the
// host level one instead. We set the return code to KERN_FAILURE to
@ -671,8 +686,9 @@ MachExceptionHandler()
reply.RetCode = KERN_FAILURE;
ret = mach_msg(&reply.header, MACH_SEND_MSG, reply.header.msgh_size, 0,
MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
if (ret != MACH_MSG_SUCCESS)
if (ret != MACH_MSG_SUCCESS) {
MOZ_CRASH("MachExceptionHandler: Failed to forward to the host level!");
}
}
}
@ -690,10 +706,11 @@ TerminateMachExceptionHandlerThread()
kern_return_t ret = mach_msg(&msg, MACH_SEND_MSG, sizeof(msg), 0, MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
if (ret == MACH_MSG_SUCCESS)
if (ret == MACH_MSG_SUCCESS) {
sMachExceptionState->handlerThread.join();
else
} else {
MOZ_CRASH("MachExceptionHandler: Handler thread failed to terminate!");
}
}
bool
@ -703,12 +720,14 @@ MemoryProtectionExceptionHandler::install()
MOZ_ASSERT(!sMachExceptionState);
// If the exception handler is disabled, report success anyway.
if (MemoryProtectionExceptionHandler::isDisabled())
if (MemoryProtectionExceptionHandler::isDisabled()) {
return true;
}
sMachExceptionState = js_new<ExceptionHandlerState>();
if (!sMachExceptionState)
if (!sMachExceptionState) {
return false;
}
kern_return_t ret;
mach_port_t task = mach_task_self();
@ -717,8 +736,9 @@ MemoryProtectionExceptionHandler::install()
sMachExceptionState->current = {};
MachExceptionParameters& current = sMachExceptionState->current;
ret = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &current.port);
if (ret != KERN_SUCCESS)
if (ret != KERN_SUCCESS) {
return false;
}
// Give the new port send rights as well.
ret = mach_port_insert_right(task, current.port, current.port, MACH_MSG_TYPE_MAKE_SEND);

Просмотреть файл

@ -35,22 +35,25 @@ class MOZ_STACK_CLASS Nestable
template <typename Predicate /* (Concrete*) -> bool */>
static Concrete* findNearest(Concrete* it, Predicate predicate) {
while (it && !predicate(it))
while (it && !predicate(it)) {
it = it->enclosing();
}
return it;
}
template <typename T>
static T* findNearest(Concrete* it) {
while (it && !it->template is<T>())
while (it && !it->template is<T>()) {
it = it->enclosing();
}
return it ? &it->template as<T>() : nullptr;
}
template <typename T, typename Predicate /* (T*) -> bool */>
static T* findNearest(Concrete* it, Predicate predicate) {
while (it && (!it->template is<T>() || !predicate(&it->template as<T>())))
while (it && (!it->template is<T>() || !predicate(&it->template as<T>()))) {
it = it->enclosing();
}
return it ? &it->template as<T>() : nullptr;
}

Просмотреть файл

@ -118,10 +118,12 @@ class OrderedHashTable
uint32_t buckets = initialBuckets();
Data** tableAlloc = alloc.template pod_malloc<Data*>(buckets);
if (!tableAlloc)
if (!tableAlloc) {
return false;
for (uint32_t i = 0; i < buckets; i++)
}
for (uint32_t i = 0; i < buckets; i++) {
tableAlloc[i] = nullptr;
}
uint32_t capacity = uint32_t(buckets * fillFactor());
Data* dataAlloc = alloc.template pod_malloc<Data>(capacity);
@ -187,8 +189,9 @@ class OrderedHashTable
// If the hashTable is more than 1/4 deleted data, simply rehash in
// place to free up some space. Otherwise, grow the table.
uint32_t newHashShift = liveCount >= dataCapacity * 0.75 ? hashShift - 1 : hashShift;
if (!rehash(newHashShift))
if (!rehash(newHashShift)) {
return false;
}
}
h >>= hashShift;
@ -230,8 +233,9 @@ class OrderedHashTable
// If many entries have been removed, try to shrink the table.
if (hashBuckets() > initialBuckets() && liveCount < dataLength * minDataFill()) {
if (!rehash(hashShift + 1))
if (!rehash(hashShift + 1)) {
return false;
}
}
return true;
}
@ -344,8 +348,9 @@ class OrderedHashTable
: ht(ht), i(0), count(0), prevp(listp), next(*listp)
{
*prevp = this;
if (next)
if (next) {
next->prevp = &next;
}
seek();
}
@ -354,14 +359,16 @@ class OrderedHashTable
: ht(other.ht), i(other.i), count(other.count), prevp(&ht->ranges), next(ht->ranges)
{
*prevp = this;
if (next)
if (next) {
next->prevp = &next;
}
}
~Range() {
*prevp = next;
if (next)
if (next) {
next->prevp = prevp;
}
}
private:
@ -369,8 +376,9 @@ class OrderedHashTable
Range& operator=(const Range& other) = delete;
void seek() {
while (i < ht->dataLength && Ops::isEmpty(Ops::getKey(ht->data[i].element)))
while (i < ht->dataLength && Ops::isEmpty(Ops::getKey(ht->data[i].element))) {
i++;
}
}
/*
@ -379,10 +387,12 @@ class OrderedHashTable
*/
void onRemove(uint32_t j) {
MOZ_ASSERT(valid());
if (j < i)
if (j < i) {
count--;
if (j == i)
}
if (j == i) {
seek();
}
}
/*
@ -470,8 +480,9 @@ class OrderedHashTable
// key's hash code changed since it was inserted, breaking the
// hash code invariant.)
Data** ep = &ht->hashTable[oldHash];
while (*ep != &entry)
while (*ep != &entry) {
ep = &(*ep)->chain;
}
*ep = entry.chain;
// Add it to the new hash chain. We could just insert it at the
@ -481,8 +492,9 @@ class OrderedHashTable
// depends on this invariant, so it's fine to kill it if
// needed.
ep = &ht->hashTable[newHash];
while (*ep && *ep > &entry)
while (*ep && *ep > &entry) {
ep = &(*ep)->chain;
}
entry.chain = *ep;
*ep = &entry;
}
@ -545,12 +557,14 @@ class OrderedHashTable
* when the entry was added to the table.
*/
void rekeyOneEntry(const Key& current, const Key& newKey, const T& element) {
if (current == newKey)
if (current == newKey) {
return;
}
Data* entry = lookup(current, prepareHash(current));
if (!entry)
if (!entry) {
return;
}
HashNumber oldHash = prepareHash(current) >> hashShift;
HashNumber newHash = prepareHash(newKey) >> hashShift;
@ -563,8 +577,9 @@ class OrderedHashTable
// key's hash code changed since it was inserted, breaking the
// hash code invariant.)
Data** ep = &hashTable[oldHash];
while (*ep != entry)
while (*ep != entry) {
ep = &(*ep)->chain;
}
*ep = entry->chain;
// Add it to the new hash chain. We could just insert it at the
@ -574,8 +589,9 @@ class OrderedHashTable
// depends on this invariant, so it's fine to kill it if
// needed.
ep = &hashTable[newHash];
while (*ep && *ep > entry)
while (*ep && *ep > entry) {
ep = &(*ep)->chain;
}
entry->chain = *ep;
*ep = entry;
}
@ -630,8 +646,9 @@ class OrderedHashTable
}
static void destroyData(Data* data, uint32_t length) {
for (Data* p = data + length; p != data; )
for (Data* p = data + length; p != data; ) {
(--p)->~Data();
}
}
void freeData(Data* data, uint32_t length, uint32_t capacity) {
@ -641,8 +658,9 @@ class OrderedHashTable
Data* lookup(const Lookup& l, HashNumber h) {
for (Data* e = hashTable[h >> hashShift]; e; e = e->chain) {
if (Ops::match(Ops::getKey(e->element), l))
if (Ops::match(Ops::getKey(e->element), l)) {
return e;
}
}
return nullptr;
}
@ -660,15 +678,17 @@ class OrderedHashTable
/* Compact the entries in |data| and rehash them. */
void rehashInPlace() {
for (uint32_t i = 0, N = hashBuckets(); i < N; i++)
for (uint32_t i = 0, N = hashBuckets(); i < N; i++) {
hashTable[i] = nullptr;
}
Data* wp = data;
Data* end = data + dataLength;
for (Data* rp = data; rp != end; rp++) {
if (!Ops::isEmpty(Ops::getKey(rp->element))) {
HashNumber h = prepareHash(Ops::getKey(rp->element)) >> hashShift;
if (rp != wp)
if (rp != wp) {
wp->element = std::move(rp->element);
}
wp->chain = hashTable[h];
hashTable[h] = wp;
wp++;
@ -676,8 +696,9 @@ class OrderedHashTable
}
MOZ_ASSERT(wp == data + liveCount);
while (wp != end)
while (wp != end) {
(--end)->~Data();
}
dataLength = liveCount;
compacted();
}
@ -700,10 +721,12 @@ class OrderedHashTable
size_t newHashBuckets =
size_t(1) << (js::kHashNumberBits - newHashShift);
Data** newHashTable = alloc.template pod_malloc<Data*>(newHashBuckets);
if (!newHashTable)
if (!newHashTable) {
return false;
for (uint32_t i = 0; i < newHashBuckets; i++)
}
for (uint32_t i = 0; i < newHashBuckets; i++) {
newHashTable[i] = nullptr;
}
uint32_t newCapacity = uint32_t(newHashBuckets * fillFactor());
Data* newData = alloc.template pod_malloc<Data>(newCapacity);
@ -820,8 +843,9 @@ class OrderedHashMap
void rekeyOneEntry(const Key& current, const Key& newKey) {
const Entry* e = get(current);
if (!e)
if (!e) {
return;
}
return impl.rekeyOneEntry(current, newKey, Entry(newKey, e->value));
}

Просмотреть файл

@ -104,17 +104,19 @@ class PageProtectingVector final
MOZ_ASSERT(protectUsedEnabled || protectUnusedEnabled);
size_t nextPage = (pageSize - (uintptr_t(begin() + length()) & pageMask)) >> elemShift;
size_t nextResize = capacity() - length();
if (MOZ_LIKELY(nextPage <= nextResize))
if (MOZ_LIKELY(nextPage <= nextResize)) {
elemsUntilTest = intptr_t(nextPage);
else
} else {
elemsUntilTest = intptr_t(nextResize);
}
}
MOZ_ALWAYS_INLINE void setTestInitial() {
if (MOZ_LIKELY(!protectUsedEnabled && !protectUnusedEnabled))
if (MOZ_LIKELY(!protectUsedEnabled && !protectUnusedEnabled)) {
elemsUntilTest = intptr_t(capacity() - length());
else
} else {
resetTest();
}
}
MOZ_ALWAYS_INLINE void resetForNewBuffer() {
@ -129,58 +131,69 @@ class PageProtectingVector final
}
MOZ_ALWAYS_INLINE void poisonNewBuffer() {
if (!PoisonUnused)
if (!PoisonUnused) {
return;
}
T* addr = begin() + length();
size_t toPoison = (capacity() - length()) * sizeof(T);
memset(addr, PoisonPattern, toPoison);
}
MOZ_ALWAYS_INLINE void addExceptionHandler() {
if (MOZ_UNLIKELY(protectUsedEnabled || protectUnusedEnabled))
if (MOZ_UNLIKELY(protectUsedEnabled || protectUnusedEnabled)) {
MemoryProtectionExceptionHandler::addRegion(begin(), capacity() << elemShift);
}
}
MOZ_ALWAYS_INLINE void removeExceptionHandler() {
if (MOZ_UNLIKELY(protectUsedEnabled || protectUnusedEnabled))
if (MOZ_UNLIKELY(protectUsedEnabled || protectUnusedEnabled)) {
MemoryProtectionExceptionHandler::removeRegion(begin());
}
}
MOZ_ALWAYS_INLINE void protectUsed() {
if (MOZ_LIKELY(!protectUsedEnabled))
if (MOZ_LIKELY(!protectUsedEnabled)) {
return;
if (MOZ_UNLIKELY(currPage <= initPage))
}
if (MOZ_UNLIKELY(currPage <= initPage)) {
return;
}
T* addr = reinterpret_cast<T*>(initPage << pageShift);
size_t size = (currPage - initPage) << pageShift;
gc::MakePagesReadOnly(addr, size);
}
MOZ_ALWAYS_INLINE void unprotectUsed() {
if (MOZ_LIKELY(!protectUsedEnabled))
if (MOZ_LIKELY(!protectUsedEnabled)) {
return;
if (MOZ_UNLIKELY(currPage <= initPage))
}
if (MOZ_UNLIKELY(currPage <= initPage)) {
return;
}
T* addr = reinterpret_cast<T*>(initPage << pageShift);
size_t size = (currPage - initPage) << pageShift;
gc::UnprotectPages(addr, size);
}
MOZ_ALWAYS_INLINE void protectUnused() {
if (MOZ_LIKELY(!protectUnusedEnabled))
if (MOZ_LIKELY(!protectUnusedEnabled)) {
return;
if (MOZ_UNLIKELY(currPage >= lastPage))
}
if (MOZ_UNLIKELY(currPage >= lastPage)) {
return;
}
T* addr = reinterpret_cast<T*>((currPage + 1) << pageShift);
size_t size = (lastPage - currPage) << pageShift;
gc::ProtectPages(addr, size);
}
MOZ_ALWAYS_INLINE void unprotectUnused() {
if (MOZ_LIKELY(!protectUnusedEnabled))
if (MOZ_LIKELY(!protectUnusedEnabled)) {
return;
if (MOZ_UNLIKELY(currPage >= lastPage))
}
if (MOZ_UNLIKELY(currPage >= lastPage)) {
return;
}
T* addr = reinterpret_cast<T*>((currPage + 1) << pageShift);
size_t size = (lastPage - currPage) << pageShift;
gc::UnprotectPages(addr, size);
@ -202,36 +215,45 @@ class PageProtectingVector final
}
MOZ_ALWAYS_INLINE void protectUnusedPartial(size_t curr, size_t next) {
if (MOZ_LIKELY(!protectUnusedEnabled))
if (MOZ_LIKELY(!protectUnusedEnabled)) {
return;
if (MOZ_UNLIKELY(next > lastPage))
}
if (MOZ_UNLIKELY(next > lastPage)) {
--next;
if (MOZ_UNLIKELY(next == curr))
}
if (MOZ_UNLIKELY(next == curr)) {
return;
}
void* addr = reinterpret_cast<T*>((curr + 1) << pageShift);
size_t size = (next - curr) << pageShift;
gc::ProtectPages(addr, size);
}
MOZ_ALWAYS_INLINE void unprotectUnusedPartial(size_t curr, size_t next) {
if (MOZ_LIKELY(!protectUnusedEnabled))
if (MOZ_LIKELY(!protectUnusedEnabled)) {
return;
if (MOZ_UNLIKELY(next > lastPage))
}
if (MOZ_UNLIKELY(next > lastPage)) {
--next;
if (MOZ_UNLIKELY(next == curr))
}
if (MOZ_UNLIKELY(next == curr)) {
return;
}
void* addr = reinterpret_cast<T*>((curr + 1) << pageShift);
size_t size = (next - curr) << pageShift;
gc::UnprotectPages(addr, size);
}
MOZ_ALWAYS_INLINE void protectUsedPartial(size_t curr, size_t next) {
if (MOZ_LIKELY(!protectUsedEnabled))
if (MOZ_LIKELY(!protectUsedEnabled)) {
return;
if (MOZ_UNLIKELY(curr < initPage))
}
if (MOZ_UNLIKELY(curr < initPage)) {
++curr;
if (MOZ_UNLIKELY(next == curr))
}
if (MOZ_UNLIKELY(next == curr)) {
return;
}
void* addr = reinterpret_cast<T*>(curr << pageShift);
size_t size = (next - curr) << pageShift;
gc::MakePagesReadOnly(addr, size);
@ -306,8 +328,9 @@ class PageProtectingVector final
protectUsedEnabled(false),
protectUnusedEnabled(false)
{
if (gc::SystemPageSize() != pageSize)
if (gc::SystemPageSize() != pageSize) {
usable = false;
}
protectNewBuffer();
}
@ -346,8 +369,9 @@ class PageProtectingVector final
if (MOZ_UNLIKELY(protectUsedEnabled)) {
uintptr_t l = uintptr_t(first) >> pageShift;
uintptr_t r = uintptr_t(first + size - 1) >> pageShift;
if (r >= initPage && l < currPage)
if (r >= initPage && l < currPage) {
unprotectRegionSlow(l, r);
}
}
}
@ -359,8 +383,9 @@ class PageProtectingVector final
if (MOZ_UNLIKELY(protectUsedEnabled)) {
uintptr_t l = uintptr_t(first) >> pageShift;
uintptr_t r = uintptr_t(first + size - 1) >> pageShift;
if (r >= initPage && l < currPage)
if (r >= initPage && l < currPage) {
reprotectRegionSlow(l, r);
}
}
}
@ -377,24 +402,27 @@ class PageProtectingVector final
}
MOZ_ALWAYS_INLINE MOZ_MUST_USE bool reserve(size_t size) {
if (MOZ_LIKELY(size <= capacity()))
if (MOZ_LIKELY(size <= capacity())) {
return vector.reserve(size);
}
return reserveSlow(size);
}
template<typename U>
MOZ_ALWAYS_INLINE void infallibleAppend(const U* values, size_t size) {
elemsUntilTest -= size;
if (MOZ_LIKELY(elemsUntilTest >= 0))
if (MOZ_LIKELY(elemsUntilTest >= 0)) {
return vector.infallibleAppend(values, size);
}
infallibleAppendSlow(values, size);
}
template<typename U>
MOZ_ALWAYS_INLINE MOZ_MUST_USE bool append(const U* values, size_t size) {
elemsUntilTest -= size;
if (MOZ_LIKELY(elemsUntilTest >= 0))
if (MOZ_LIKELY(elemsUntilTest >= 0)) {
return vector.append(values, size);
}
return appendSlow(values, size);
}
};
@ -403,10 +431,12 @@ template<typename T, size_t A, class B, bool C, bool D, size_t E, bool F, uint8_
MOZ_NEVER_INLINE void
PageProtectingVector<T, A, B, C, D, E, F, G>::unprotectRegionSlow(uintptr_t l, uintptr_t r)
{
if (l < initPage)
if (l < initPage) {
l = initPage;
if (r >= currPage)
}
if (r >= currPage) {
r = currPage - 1;
}
T* addr = reinterpret_cast<T*>(l << pageShift);
size_t size = (r - l + 1) << pageShift;
gc::UnprotectPages(addr, size);
@ -416,10 +446,12 @@ template<typename T, size_t A, class B, bool C, bool D, size_t E, bool F, uint8_
MOZ_NEVER_INLINE void
PageProtectingVector<T, A, B, C, D, E, F, G>::reprotectRegionSlow(uintptr_t l, uintptr_t r)
{
if (l < initPage)
if (l < initPage) {
l = initPage;
if (r >= currPage)
}
if (r >= currPage) {
r = currPage - 1;
}
T* addr = reinterpret_cast<T*>(l << pageShift);
size_t size = (r - l + 1) << pageShift;
gc::MakePagesReadOnly(addr, size);
@ -449,8 +481,9 @@ template<typename U>
MOZ_NEVER_INLINE MOZ_MUST_USE bool
PageProtectingVector<T, A, B, C, D, E, F, G>::appendSlow(const U* values, size_t size)
{
if (MOZ_LIKELY(length() + size <= capacity()))
if (MOZ_LIKELY(length() + size <= capacity())) {
return appendNewPage(values, size);
}
return appendNewBuffer(values, size);
}

Просмотреть файл

@ -58,8 +58,9 @@ class PriorityQueue
}
MOZ_MUST_USE bool insert(const T& v) {
if (!heap.append(v))
if (!heap.append(v)) {
return false;
}
siftUp(heap.length() - 1);
return true;
}
@ -115,8 +116,9 @@ class PriorityQueue
while (n > 0) {
size_t parent = (n - 1) / 2;
if (P::priority(heap[parent]) > P::priority(heap[n]))
if (P::priority(heap[parent]) > P::priority(heap[n])) {
break;
}
swap(n, parent);
n = parent;

Просмотреть файл

@ -35,14 +35,16 @@ MergeArrayRuns(T* dst, const T* src, size_t run1, size_t run2, Comparator c)
/* Copy runs already in sorted order. */
const T* b = src + run1;
bool lessOrEqual;
if (!c(b[-1], b[0], &lessOrEqual))
if (!c(b[-1], b[0], &lessOrEqual)) {
return false;
}
if (!lessOrEqual) {
/* Runs are not already sorted, merge them. */
for (const T* a = src;;) {
if (!c(*a, *b, &lessOrEqual))
if (!c(*a, *b, &lessOrEqual)) {
return false;
}
if (lessOrEqual) {
*dst++ = *a++;
if (!--run1) {
@ -83,8 +85,9 @@ MergeSort(T* array, size_t nelems, T* scratch, Comparator c)
{
const size_t INS_SORT_LIMIT = 3;
if (nelems <= 1)
if (nelems <= 1) {
return true;
}
/*
* Apply insertion sort to small chunks to reduce the number of merge
@ -92,20 +95,24 @@ MergeSort(T* array, size_t nelems, T* scratch, Comparator c)
*/
for (size_t lo = 0; lo < nelems; lo += INS_SORT_LIMIT) {
size_t hi = lo + INS_SORT_LIMIT;
if (hi >= nelems)
if (hi >= nelems) {
hi = nelems;
}
for (size_t i = lo + 1; i != hi; i++) {
for (size_t j = i; ;) {
bool lessOrEqual;
if (!c(array[j - 1], array[j], &lessOrEqual))
if (!c(array[j - 1], array[j], &lessOrEqual)) {
return false;
if (lessOrEqual)
}
if (lessOrEqual) {
break;
}
T tmp = array[j - 1];
array[j - 1] = array[j];
array[j] = tmp;
if (--j == lo)
if (--j == lo) {
break;
}
}
}
}
@ -120,15 +127,17 @@ MergeSort(T* array, size_t nelems, T* scratch, Comparator c)
break;
}
size_t run2 = (run <= nelems - hi) ? run : nelems - hi;
if (!detail::MergeArrayRuns(vec2 + lo, vec1 + lo, run, run2, c))
if (!detail::MergeArrayRuns(vec2 + lo, vec1 + lo, run, run2, c)) {
return false;
}
}
T* swap = vec1;
vec1 = vec2;
vec2 = swap;
}
if (vec1 == scratch)
if (vec1 == scratch) {
detail::CopyNonEmptyArray(array, scratch, nelems);
}
return true;
}

Просмотреть файл

@ -70,16 +70,18 @@ class SplayTree
T* maybeLookup(const T& v)
{
if (!root)
if (!root) {
return nullptr;
}
Node* last = lookup(v);
return (C::compare(v, last->item) == 0) ? &(last->item) : nullptr;
}
bool contains(const T& v, T* res)
{
if (!root)
if (!root) {
return false;
}
Node* last = lookup(v);
splay(last);
checkCoherency();
@ -93,8 +95,9 @@ class SplayTree
MOZ_MUST_USE bool insert(const T& v)
{
Node* element = allocateNode(v);
if (!element)
if (!element) {
return false;
}
if (!root) {
root = element;
@ -131,13 +134,15 @@ class SplayTree
Node* swapChild;
if (root->left) {
swap = root->left;
while (swap->right)
while (swap->right) {
swap = swap->right;
}
swapChild = swap->left;
} else if (root->right) {
swap = root->right;
while (swap->left)
while (swap->left) {
swap = swap->left;
}
swapChild = swap->right;
} else {
freeNode(root);
@ -147,12 +152,14 @@ class SplayTree
// The selected node has at most one child, in swapChild. Detach it
// from the subtree by replacing it with that child.
if (swap == swap->parent->left)
if (swap == swap->parent->left) {
swap->parent->left = swapChild;
else
} else {
swap->parent->right = swapChild;
if (swapChild)
}
if (swapChild) {
swapChild->parent = swap->parent;
}
root->item = swap->item;
freeNode(swap);
@ -176,12 +183,13 @@ class SplayTree
do {
parent = node;
int c = C::compare(v, node->item);
if (c == 0)
if (c == 0) {
return node;
else if (c < 0)
} else if (c < 0) {
node = node->left;
else
} else {
node = node->right;
}
} while (node);
return parent;
}
@ -240,8 +248,9 @@ class SplayTree
// y c ==> a x
// a b b c
parent->left = node->right;
if (node->right)
if (node->right) {
node->right->parent = parent;
}
node->right = parent;
} else {
MOZ_ASSERT(parent->right == node);
@ -249,17 +258,19 @@ class SplayTree
// a y ==> x c
// b c a b
parent->right = node->left;
if (node->left)
if (node->left) {
node->left->parent = parent;
}
node->left = parent;
}
node->parent = parent->parent;
parent->parent = node;
if (Node* grandparent = node->parent) {
if (grandparent->left == parent)
if (grandparent->left == parent) {
grandparent->left = node;
else
} else {
grandparent->right = node;
}
} else {
root = node;
}
@ -268,8 +279,9 @@ class SplayTree
template <class Op>
void forEachInner(Op op, Node* node)
{
if (!node)
if (!node) {
return;
}
forEachInner<Op>(op, node->left);
op(node->item);
@ -279,10 +291,12 @@ class SplayTree
void checkCoherency() const
{
#ifdef DEBUG
if (!enableCheckCoherency)
if (!enableCheckCoherency) {
return;
if (!root)
}
if (!root) {
return;
}
MOZ_ASSERT(root->parent == nullptr);
const Node* node = root;
const Node* minimum = nullptr;
@ -328,8 +342,9 @@ class SplayTree
minimum = node;
}
if (node->right != prev && node->right != nullptr)
if (node->right != prev && node->right != nullptr) {
break;
}
}
if (!node->parent) {
@ -337,8 +352,9 @@ class SplayTree
// We reached the root node either because we came back from
// the right hand side, or because the root node had a
// single child.
if (node->right == prev || node->right == nullptr)
if (node->right == prev || node->right == nullptr) {
return;
}
}
// Go to the right node which we have not visited yet.

Просмотреть файл

@ -45,10 +45,12 @@ class TraceableFifo : public js::Fifo<T, MinInlineCapacity, AllocPolicy>
TraceableFifo& operator=(const TraceableFifo&) = delete;
void trace(JSTracer* trc) {
for (size_t i = 0; i < this->front_.length(); ++i)
for (size_t i = 0; i < this->front_.length(); ++i) {
JS::GCPolicy<T>::trace(trc, &this->front_[i], "fifo element");
for (size_t i = 0; i < this->rear_.length(); ++i)
}
for (size_t i = 0; i < this->rear_.length(); ++i) {
JS::GCPolicy<T>::trace(trc, &this->rear_[i], "fifo element");
}
}
};

Просмотреть файл

@ -26,6 +26,7 @@
#include "jit/JitFrames-inl.h"
#include "jit/MacroAssembler-inl.h"
#include "vm/BytecodeUtil-inl.h"
#include "vm/GeckoProfiler-inl.h"
#include "vm/JSObject-inl.h"
#include "vm/JSScript-inl.h"
#include "vm/Stack-inl.h"
@ -252,6 +253,7 @@ jit::BaselineCompile(JSContext* cx, JSScript* script, bool forceDebugInstrumenta
MOZ_ASSERT(!script->hasBaselineScript());
MOZ_ASSERT(script->canBaselineCompile());
MOZ_ASSERT(IsBaselineEnabled(cx));
AutoGeckoProfilerEntry pseudoFrame(cx, "Baseline script compilation");
script->ensureNonLazyCanonicalFunction();

Просмотреть файл

@ -60,6 +60,7 @@
#include "jit/shared/Lowering-shared-inl.h"
#include "vm/Debugger-inl.h"
#include "vm/EnvironmentObject-inl.h"
#include "vm/GeckoProfiler-inl.h"
#include "vm/JSObject-inl.h"
#include "vm/JSScript-inl.h"
#include "vm/Realm-inl.h"
@ -2374,6 +2375,7 @@ Compile(JSContext* cx, HandleScript script, BaselineFrame* osrFrame, jsbytecode*
MOZ_ASSERT(jit::IsIonEnabled(cx));
MOZ_ASSERT(jit::IsBaselineEnabled(cx));
MOZ_ASSERT_IF(osrPc != nullptr, LoopEntryCanIonOsr(osrPc));
AutoGeckoProfilerEntry pseudoFrame(cx, "Ion script compilation");
if (!script->hasBaselineScript()) {
return Method_Skipped;

Просмотреть файл

@ -378,9 +378,17 @@ var FormAssistant = {
scrollY += rect.top + parseInt(top);
}
// The rect computed above is relative to the origin of the viewport frame,
// i.e. the layout viewport origin, but the consumer of the
// FormAssist::AutoCompleteResult messaage expects a rect relative to
// the visual viewport origin, so translate between the two.
let offsetX = {}, offsetY = {};
aElement.ownerGlobal.windowUtils
.getVisualViewportOffsetRelativeToLayoutViewport(offsetX, offsetY);
return {
x: r.left + scrollX,
y: r.top + scrollY,
x: r.left + scrollX - offsetX.value,
y: r.top + scrollY - offsetY.value,
w: r.width,
h: r.height,
};

Просмотреть файл

@ -152,8 +152,8 @@ public:
return false;
}
mPatchedFns.append(reinterpret_cast<void*>(readOnlyTargetFn.GetBaseAddress()));
return true;
return mPatchedFns.append(
reinterpret_cast<void*>(readOnlyTargetFn.GetBaseAddress()));
}
bool WriteHook(const ReadOnlyTargetFunction<MMPolicyT>& aFn,
@ -169,7 +169,7 @@ public:
// Check that the 5 bytes before the function are NOP's or INT 3's,
const uint8_t nopOrBp[] = { 0x90, 0xCC };
if (!writableFn.VerifyValuesAreOneOf<uint8_t, 5>(nopOrBp)) {
if (!writableFn.template VerifyValuesAreOneOf<uint8_t, 5>(nopOrBp)) {
return false;
}
@ -184,7 +184,8 @@ public:
// (These look backwards because little-endian)
const uint16_t possibleEncodings[] = { 0xFF8B, 0xFF89 };
if (!writableFn.VerifyValuesAreOneOf<uint16_t, 1>(possibleEncodings, 5)) {
if (!writableFn.template VerifyValuesAreOneOf<uint16_t, 1>(
possibleEncodings, 5)) {
return false;
}

Просмотреть файл

@ -20,6 +20,27 @@
namespace mozilla {
namespace interceptor {
#if defined(_M_IX86)
template <typename T> bool
CommitAndWriteShortInternal(const T& aMMPolicy, void* aDest, uint16_t aValue);
template <> inline bool
CommitAndWriteShortInternal<MMPolicyInProcess>(
const MMPolicyInProcess& aMMPolicy, void* aDest, uint16_t aValue)
{
return aMMPolicy.WriteAtomic(aDest, aValue);
}
template <> inline bool
CommitAndWriteShortInternal<MMPolicyOutOfProcess>(
const MMPolicyOutOfProcess& aMMPolicy, void* aDest, uint16_t aValue)
{
return aMMPolicy.Write(aDest, &aValue, sizeof(uint16_t));
}
#endif // defined(_M_IX86)
template <typename MMPolicy>
class MOZ_STACK_CLASS WritableTargetFunction final
{
@ -233,24 +254,6 @@ public:
}
#if defined(_M_IX86)
private:
template <typename T>
bool CommitAndWriteShortInternal(const T& aMMPolicy, void* aDest, uint16_t aValue);
template <>
bool CommitAndWriteShortInternal<MMPolicyInProcess>(const MMPolicyInProcess& aMMPolicy,
void* aDest, uint16_t aValue)
{
return aMMPolicy.WriteAtomic(aDest, aValue);
}
template <>
bool CommitAndWriteShortInternal<MMPolicyOutOfProcess>(const MMPolicyOutOfProcess& aMMPolicy,
void* aDest, uint16_t aValue)
{
return aMMPolicy.Write(aDest, &aValue, sizeof(uint16_t));
}
public:
/**
* Commits any dirty writes, and then writes a short, atomically if possible.
@ -595,82 +598,81 @@ private:
uint8_t const * const mBase;
};
template <typename TargetMMPolicy> class TargetBytesPtr;
template<>
class TargetBytesPtr<MMPolicyInProcess>
{
public:
typedef TargetBytesPtr<MMPolicyInProcess> Type;
static Type Make(const MMPolicyInProcess& aMMPolicy, const void* aFunc)
{
return TargetBytesPtr(aMMPolicy, aFunc);
}
static Type CopyFromOffset(const TargetBytesPtr& aOther,
const uint32_t aOffsetFromOther)
{
return TargetBytesPtr(aOther, aOffsetFromOther);
}
ReadOnlyTargetBytes<MMPolicyInProcess>* operator->()
{
return &mTargetBytes;
}
TargetBytesPtr(TargetBytesPtr&& aOther)
: mTargetBytes(std::move(aOther.mTargetBytes))
{
}
TargetBytesPtr(const TargetBytesPtr& aOther)
: mTargetBytes(aOther.mTargetBytes)
{
}
TargetBytesPtr& operator=(const TargetBytesPtr&) = delete;
TargetBytesPtr& operator=(TargetBytesPtr&&) = delete;
private:
TargetBytesPtr(const MMPolicyInProcess& aMMPolicy, const void* aFunc)
: mTargetBytes(aMMPolicy, aFunc)
{
}
TargetBytesPtr(const TargetBytesPtr& aOther,
const uint32_t aOffsetFromOther)
: mTargetBytes(aOther.mTargetBytes, aOffsetFromOther)
{
}
ReadOnlyTargetBytes<MMPolicyInProcess> mTargetBytes;
};
template <>
class TargetBytesPtr<MMPolicyOutOfProcess>
{
public:
typedef std::shared_ptr<ReadOnlyTargetBytes<MMPolicyOutOfProcess>> Type;
static Type Make(const MMPolicyOutOfProcess& aMMPolicy, const void* aFunc)
{
return std::make_shared<ReadOnlyTargetBytes<MMPolicyOutOfProcess>>(
aMMPolicy, aFunc);
}
static Type CopyFromOffset(const Type& aOther,
const uint32_t aOffsetFromOther)
{
return std::make_shared<ReadOnlyTargetBytes<MMPolicyOutOfProcess>>(
*aOther, aOffsetFromOther);
}
};
template <typename MMPolicy>
class MOZ_STACK_CLASS ReadOnlyTargetFunction final
{
template <typename TargetMMPolicy>
class TargetBytesPtr;
template<>
class TargetBytesPtr<MMPolicyInProcess>
{
public:
typedef TargetBytesPtr<MMPolicyInProcess> Type;
static Type Make(const MMPolicyInProcess& aMMPolicy, const void* aFunc)
{
return std::move(TargetBytesPtr(aMMPolicy, aFunc));
}
static Type CopyFromOffset(const TargetBytesPtr& aOther,
const uint32_t aOffsetFromOther)
{
return std::move(TargetBytesPtr(aOther, aOffsetFromOther));
}
ReadOnlyTargetBytes<MMPolicyInProcess>* operator->()
{
return &mTargetBytes;
}
TargetBytesPtr(TargetBytesPtr&& aOther)
: mTargetBytes(std::move(aOther.mTargetBytes))
{
}
TargetBytesPtr(const TargetBytesPtr& aOther)
: mTargetBytes(aOther.mTargetBytes)
{
}
TargetBytesPtr& operator=(const TargetBytesPtr&) = delete;
TargetBytesPtr& operator=(TargetBytesPtr&&) = delete;
private:
TargetBytesPtr(const MMPolicyInProcess& aMMPolicy, const void* aFunc)
: mTargetBytes(aMMPolicy, aFunc)
{
}
TargetBytesPtr(const TargetBytesPtr& aOther,
const uint32_t aOffsetFromOther)
: mTargetBytes(aOther.mTargetBytes, aOffsetFromOther)
{
}
ReadOnlyTargetBytes<MMPolicyInProcess> mTargetBytes;
};
template <>
class TargetBytesPtr<MMPolicyOutOfProcess>
{
public:
typedef std::shared_ptr<ReadOnlyTargetBytes<MMPolicyOutOfProcess>> Type;
static Type Make(const MMPolicyOutOfProcess& aMMPolicy, const void* aFunc)
{
return std::move(std::make_shared<ReadOnlyTargetBytes<MMPolicyOutOfProcess>>(
aMMPolicy, aFunc));
}
static Type CopyFromOffset(const Type& aOther,
const uint32_t aOffsetFromOther)
{
return std::move(std::make_shared<ReadOnlyTargetBytes<MMPolicyOutOfProcess>>(
*aOther, aOffsetFromOther));
}
};
public:
ReadOnlyTargetFunction(const MMPolicy& aMMPolicy, const void* aFunc)
: mTargetBytes(TargetBytesPtr<MMPolicy>::Make(aMMPolicy, aFunc))

Просмотреть файл

@ -6,15 +6,13 @@
#include "nsISupports.idl"
interface mozIDOMWindowProxy;
interface nsIDocShell;
interface nsITransportSecurityInfo;
[scriptable, uuid(718c662a-f810-4a80-a6c9-0b1810ecade2)]
interface nsISecureBrowserUI : nsISupports
{
void init(in mozIDOMWindowProxy window);
void setDocShell(in nsIDocShell docShell);
void init(in nsIDocShell docShell);
readonly attribute unsigned long state;
readonly attribute nsITransportSecurityInfo secInfo;

Просмотреть файл

@ -391,6 +391,11 @@ CookieServiceChild::GetCookieStringFromCookieHashTable(nsIURI *a
if (!nsCookieService::DomainMatches(cookie, hostFromURI))
continue;
// We don't show HttpOnly cookies in content processes.
if (cookie->IsHttpOnly()) {
continue;
}
// if the cookie is secure and the host scheme isn't, we can't send it
if (cookie->IsSecure() && !isSecure)
continue;
@ -521,9 +526,7 @@ CookieServiceChild::RecordDocumentCookie(nsCookie *aCookie,
return;
}
if (!aCookie->IsHttpOnly()) {
cookiesList->AppendElement(aCookie);
}
cookiesList->AppendElement(aCookie);
}
nsresult
@ -677,19 +680,38 @@ CookieServiceChild::SetCookieStringInternal(nsIURI *aHostURI,
return NS_OK;
}
nsCookieKey key(baseDomain, attrs);
CookiesList *cookies = mCookiesMap.Get(key);
nsCString serverTimeString(aServerTime);
int64_t serverTime = nsCookieService::ParseServerTime(serverTimeString);
bool moreCookies;
do {
nsCookieAttributes cookieAttributes;
bool canSetCookie = false;
nsCookieKey key(baseDomain, attrs);
moreCookies = nsCookieService::CanSetCookie(aHostURI, key, cookieAttributes,
requireHostMatch, cookieStatus,
cookieString, serverTime, aFromHttp,
aChannel, mLeaveSecureAlone,
canSetCookie, mThirdPartyUtil);
// We need to see if the cookie we're setting would overwrite an httponly
// one. This would not affect anything we send over the net (those come from
// the parent, which already checks this), but script could see an
// inconsistent view of things.
if (cookies && canSetCookie && !aFromHttp) {
for (uint32_t i = 0; i < cookies->Length(); ++i) {
RefPtr<nsCookie> cookie = cookies->ElementAt(i);
if (cookie->Name().Equals(cookieAttributes.name) &&
cookie->Host().Equals(cookieAttributes.host) &&
cookie->Path().Equals(cookieAttributes.path) &&
cookie->IsHttpOnly()) {
// Can't overwrite an httponly cookie from a script context.
canSetCookie = false;
}
}
}
if (canSetCookie) {
SetCookieInternal(cookieAttributes, attrs, aChannel,
aFromHttp, permissionService);

Просмотреть файл

@ -100,10 +100,12 @@ CookieServiceParent::RemoveBatchDeletedCookies(nsIArray *aCookieList) {
auto cookie = static_cast<nsCookie*>(xpcCookie.get());
attrs = cookie->OriginAttributesRef();
GetInfoFromCookie(cookie, cookieStruct);
if (!cookie->IsHttpOnly()) {
cookieStructList.AppendElement(cookieStruct);
attrsList.AppendElement(attrs);
if (cookie->IsHttpOnly()) {
// Child only needs to exist if an HttpOnly cookie exists, not its value
cookieStruct.value() = "";
}
cookieStructList.AppendElement(cookieStruct);
attrsList.AppendElement(attrs);
}
Unused << SendRemoveBatchDeletedCookies(cookieStructList, attrsList);
}
@ -121,9 +123,10 @@ CookieServiceParent::RemoveCookie(nsICookie *aCookie)
OriginAttributes attrs = cookie->OriginAttributesRef();
CookieStruct cookieStruct;
GetInfoFromCookie(cookie, cookieStruct);
if (!cookie->IsHttpOnly()) {
Unused << SendRemoveCookie(cookieStruct, attrs);
if (cookie->IsHttpOnly()) {
cookieStruct.value() = "";
}
Unused << SendRemoveCookie(cookieStruct, attrs);
}
void
@ -133,6 +136,9 @@ CookieServiceParent::AddCookie(nsICookie *aCookie)
OriginAttributes attrs = cookie->OriginAttributesRef();
CookieStruct cookieStruct;
GetInfoFromCookie(cookie, cookieStruct);
if (cookie->IsHttpOnly()) {
cookieStruct.value() = "";
}
Unused << SendAddCookie(cookieStruct, attrs);
}
@ -191,7 +197,9 @@ CookieServiceParent::SerialializeCookieList(const nsTArray<nsCookie*> &aFoundCoo
nsCookie *cookie = aFoundCookieList.ElementAt(i);
CookieStruct* cookieStruct = aCookiesList.AppendElement();
cookieStruct->name() = cookie->Name();
cookieStruct->value() = cookie->Value();
if (!cookie->IsHttpOnly()) {
cookieStruct->value() = cookie->Value();
}
cookieStruct->host() = cookie->Host();
cookieStruct->path() = cookie->Path();
cookieStruct->expiry() = cookie->Expiry();

Просмотреть файл

@ -18,6 +18,7 @@
#include "nsIAuthPromptProvider.h"
#include "nsIEncodedChannel.h"
#include "nsIHttpChannelInternal.h"
#include "nsISecureBrowserUI.h"
#include "nsIForcePendingChannel.h"
#include "mozilla/ipc/IPCStreamUtils.h"
#include "mozilla/ipc/URIUtils.h"

Просмотреть файл

@ -47,6 +47,7 @@
#include "mozilla/net/RedirectChannelRegistrar.h"
#include "nsIWindowWatcher.h"
#include "nsIDocument.h"
#include "nsISecureBrowserUI.h"
#include "nsStreamUtils.h"
#include "nsStringStream.h"
#include "nsIStorageStream.h"

Просмотреть файл

@ -0,0 +1,125 @@
# coding=utf8
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
from __future__ import absolute_import
import fluent.syntax.ast as FTL
from fluent.migrate.helpers import transforms_from, VARIABLE_REFERENCE
from fluent.migrate import REPLACE, COPY
def migrate(ctx):
"""Bug 1486936 - Convert about:config to using Fluent for localization, part {index}."""
ctx.add_transforms(
"toolkit/toolkit/about/aboutConfig.ftl",
"toolkit/toolkit/about/aboutConfig.ftl",
transforms_from(
"""
config-window =
.title = { COPY(from_path, "window.title") }
config-about-warning-title =
.value = { COPY(from_path, "aboutWarningTitle.label") }
config-about-warning-text = { COPY(from_path, "aboutWarningText.label") }
config-about-warning-button =
.label = { COPY(from_path, "aboutWarningButton2.label") }
config-about-warning-checkbox =
.label = { COPY(from_path, "aboutWarningCheckbox.label") }
config-search-prefs =
.value = { COPY(from_path, "searchPrefs.label") }
.accesskey = { COPY(from_path, "searchPrefs.accesskey") }
config-focus-search =
.key = { COPY(from_path, "focusSearch.key") }
config-focus-search-2 =
.key = { COPY(from_path, "focusSearch2.key") }
config-pref-column =
.label = { COPY(from_path, "prefColumn.label") }
config-lock-column =
.label = { COPY(from_path, "lockColumn.label") }
config-type-column =
.label = { COPY(from_path, "typeColumn.label") }
config-value-column =
.label = { COPY(from_path, "valueColumn.label") }
config-pref-column-header =
.tooltip = { COPY(from_path, "prefColumnHeader.tooltip") }
config-column-chooser =
.tooltip = { COPY(from_path, "columnChooser.tooltip") }
config-copy-pref =
.key = { COPY(from_path, "copyPref.key") }
.label = { COPY(from_path, "copyPref.label") }
.accesskey = { COPY(from_path, "copyPref.accesskey") }
config-copy-name =
.label = { COPY(from_path, "copyName.label") }
.accesskey = { COPY(from_path, "copyName.accesskey") }
config-copy-value =
.label = { COPY(from_path, "copyValue.label") }
.accesskey = { COPY(from_path, "copyValue.accesskey") }
config-modify =
.label = { COPY(from_path, "modify.label") }
.accesskey = { COPY(from_path, "modify.accesskey") }
config-toggle =
.label = { COPY(from_path, "toggle.label") }
.accesskey = { COPY(from_path, "toggle.accesskey") }
config-reset =
.label = { COPY(from_path, "reset.label") }
.accesskey = { COPY(from_path, "reset.accesskey") }
config-new =
.label = { COPY(from_path, "new.label") }
.accesskey = { COPY(from_path, "new.accesskey") }
config-string =
.label = { COPY(from_path, "string.label") }
.accesskey = { COPY(from_path, "string.accesskey") }
config-integer =
.label = { COPY(from_path, "integer.label") }
.accesskey = { COPY(from_path, "integer.accesskey") }
config-boolean =
.label = { COPY(from_path, "boolean.label") }
.accesskey = { COPY(from_path, "boolean.accesskey") }
""", from_path="toolkit/chrome/global/config.dtd"))
ctx.add_transforms(
"toolkit/toolkit/about/aboutConfig.ftl",
"toolkit/toolkit/about/aboutConfig.ftl",
transforms_from(
"""
config-default = { COPY(from_path, "default") }
config-modified = { COPY(from_path, "modified") }
config-locked = { COPY(from_path, "locked") }
config-property-string = { COPY(from_path, "string") }
config-property-int = { COPY(from_path, "int") }
config-property-bool = { COPY(from_path, "bool") }
config-new-prompt = { COPY(from_path, "new_prompt") }
config-nan-title = { COPY(from_path, "nan_title") }
config-nan-text = { COPY(from_path, "nan_text") }
""", from_path="toolkit/chrome/global/config.properties"))
ctx.add_transforms(
"toolkit/toolkit/about/aboutConfig.ftl",
"toolkit/toolkit/about/aboutConfig.ftl",
[
FTL.Message(
id=FTL.Identifier("config-new-title"),
value=REPLACE(
"toolkit/chrome/global/config.properties",
"new_title",
{
"%S": VARIABLE_REFERENCE(
"type"
),
}
)
),
FTL.Message(
id=FTL.Identifier("config-modify-title"),
value=REPLACE(
"toolkit/chrome/global/config.properties",
"modify_title",
{
"%S": VARIABLE_REFERENCE(
"type"
),
}
)
),
]
)

Просмотреть файл

@ -206,16 +206,20 @@ NSSCertDBTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
// certificates.
if (mCertDBTrustType == trustSSL) {
bool isCertRevoked;
nsresult nsrv = mCertBlocklist->IsCertRevoked(
candidateCert->derIssuer.data,
candidateCert->derIssuer.len,
candidateCert->serialNumber.data,
candidateCert->serialNumber.len,
candidateCert->derSubject.data,
candidateCert->derSubject.len,
candidateCert->derPublicKey.data,
candidateCert->derPublicKey.len,
&isCertRevoked);
nsAutoCString encIssuer;
nsAutoCString encSerial;
nsAutoCString encSubject;
nsAutoCString encPubKey;
nsresult nsrv = BuildRevocationCheckStrings(candidateCert.get(), encIssuer, encSerial, encSubject, encPubKey);
if (NS_FAILED(nsrv)) {
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
nsrv = mCertBlocklist->IsCertRevoked(
encIssuer, encSerial, encSubject, encPubKey, &isCertRevoked);
if (NS_FAILED(nsrv)) {
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
@ -1285,6 +1289,47 @@ DefaultServerNicknameForCert(const CERTCertificate* cert,
return NS_ERROR_FAILURE;
}
nsresult
BuildRevocationCheckStrings(const CERTCertificate* cert,
/*out*/ nsCString& encIssuer,
/*out*/ nsCString& encSerial,
/*out*/ nsCString& encSubject,
/*out*/ nsCString& encPubKey)
{
// Convert issuer, serial, subject and pubKey data to Base64 encoded DER
nsDependentCSubstring issuerString(
BitwiseCast<char*, uint8_t*>(cert->derIssuer.data),
cert->derIssuer.len);
nsDependentCSubstring serialString(
BitwiseCast<char*, uint8_t*>(cert->serialNumber.data),
cert->serialNumber.len);
nsDependentCSubstring subjectString(
BitwiseCast<char*, uint8_t*>(cert->derSubject.data),
cert->derSubject.len);
nsDependentCSubstring pubKeyString(
BitwiseCast<char*, uint8_t*>(cert->derPublicKey.data),
cert->derPublicKey.len);
nsresult rv = Base64Encode(issuerString, encIssuer);
if (NS_FAILED(rv)) {
return rv;
}
rv = Base64Encode(serialString, encSerial);
if (NS_FAILED(rv)) {
return rv;
}
rv = Base64Encode(subjectString, encSubject);
if (NS_FAILED(rv)) {
return rv;
}
rv = Base64Encode(pubKeyString, encPubKey);
if (NS_FAILED(rv)) {
return rv;
}
return NS_OK;
}
/**
* Given a list of certificates representing a verified certificate path from an
* end-entity certificate to a trust anchor, imports the intermediate

Просмотреть файл

@ -58,6 +58,30 @@ void UnloadLoadableRoots();
nsresult DefaultServerNicknameForCert(const CERTCertificate* cert,
/*out*/ nsCString& nickname);
/**
* Build strings of base64 encoded issuer, serial, subject and public key data
* from the supplied certificate for use in revocation checks.
*
* @param cert
* The CERTCertificate* from which to extract the data.
* @param out encIssuer
* The string to populate with base64 encoded issuer data.
* @param out encSerial
* The string to populate with base64 encoded serial number data.
* @param out encSubject
* The string to populate with base64 encoded subject data.
* @param out encPubKey
* The string to populate with base64 encoded public key data.
* @return
* NS_OK, unless there's a Base64 encoding problem, in which case
* NS_ERROR_FAILURE.
*/
nsresult BuildRevocationCheckStrings(const CERTCertificate* cert,
/*out*/ nsCString& encIssuer,
/*out*/ nsCString& encSerial,
/*out*/ nsCString& encSubject,
/*out*/ nsCString& encPubKey);
void SaveIntermediateCerts(const UniqueCERTCertList& certList);
class NSSCertDBTrustDomain : public mozilla::pkix::TrustDomain

Просмотреть файл

@ -9,6 +9,7 @@
#include "mozilla/Preferences.h"
#include "nsNSSCertificate.h"
#include "nsNSSComponent.h"
#include "NSSCertDBTrustDomain.h"
#include "nsServiceManagerUtils.h"
#include "nsThreadUtils.h"
#include "pkix/pkixnss.h"
@ -44,17 +45,19 @@ CSTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
return MapPRErrorCodeToResult(PR_GetError());
}
nsAutoCString encIssuer;
nsAutoCString encSerial;
nsAutoCString encSubject;
nsAutoCString encPubKey;
nsresult nsrv = BuildRevocationCheckStrings(candidateCert.get(), encIssuer, encSerial, encSubject, encPubKey);
if (NS_FAILED(nsrv)) {
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
bool isCertRevoked;
nsresult nsrv = mCertBlocklist->IsCertRevoked(
candidateCert->derIssuer.data,
candidateCert->derIssuer.len,
candidateCert->serialNumber.data,
candidateCert->serialNumber.len,
candidateCert->derSubject.data,
candidateCert->derSubject.len,
candidateCert->derPublicKey.data,
candidateCert->derPublicKey.len,
&isCertRevoked);
nsrv = mCertBlocklist->IsCertRevoked(
encIssuer, encSerial, encSubject, encPubKey, &isCertRevoked);
if (NS_FAILED(nsrv)) {
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}

Просмотреть файл

@ -508,48 +508,54 @@ CertBlocklist::SaveEntries()
}
NS_IMETHODIMP
CertBlocklist::IsCertRevoked(const uint8_t* aIssuer,
uint32_t aIssuerLength,
const uint8_t* aSerial,
uint32_t aSerialLength,
const uint8_t* aSubject,
uint32_t aSubjectLength,
const uint8_t* aPubKey,
uint32_t aPubKeyLength,
CertBlocklist::IsCertRevoked(const nsACString& aIssuerString,
const nsACString& aSerialNumberString,
const nsACString& aSubjectString,
const nsACString& aPubKeyString,
bool* _retval)
{
MutexAutoLock lock(mMutex);
MOZ_LOG(gCertBlockPRLog, LogLevel::Warning, ("CertBlocklist::IsCertRevoked"));
MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
("CertBlocklist::IsCertRevoked?"));
nsresult rv = EnsureBackingFileInitialized(lock);
nsCString decodedIssuer;
nsCString decodedSerial;
nsCString decodedSubject;
nsCString decodedPubKey;
nsresult rv = Base64Decode(aIssuerString, decodedIssuer);
if (NS_FAILED(rv)) {
return rv;
}
rv = Base64Decode(aSerialNumberString, decodedSerial);
if (NS_FAILED(rv)) {
return rv;
}
rv = Base64Decode(aSubjectString, decodedSubject);
if (NS_FAILED(rv)) {
return rv;
}
rv = Base64Decode(aPubKeyString, decodedPubKey);
if (NS_FAILED(rv)) {
return rv;
}
Input issuer;
Input serial;
if (issuer.Init(aIssuer, aIssuerLength) != Success) {
return NS_ERROR_FAILURE;
}
if (serial.Init(aSerial, aSerialLength) != Success) {
return NS_ERROR_FAILURE;
}
CertBlocklistItem issuerSerial(aIssuer, aIssuerLength, aSerial, aSerialLength,
BlockByIssuerAndSerial);
nsAutoCString encDN;
nsAutoCString encOther;
issuerSerial.ToBase64(encDN, encOther);
rv = EnsureBackingFileInitialized(lock);
if (NS_FAILED(rv)) {
return rv;
}
MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
CertBlocklistItem issuerSerial(
BitwiseCast<const uint8_t*, const char*>(decodedIssuer.get()),
decodedIssuer.Length(),
BitwiseCast<const uint8_t*, const char*>(decodedSerial.get()),
decodedSerial.Length(),
BlockByIssuerAndSerial);
MOZ_LOG(gCertBlockPRLog,
LogLevel::Warning,
("CertBlocklist::IsCertRevoked issuer %s - serial %s",
encDN.get(), encOther.get()));
PromiseFlatCString(aIssuerString).get(),
PromiseFlatCString(aSerialNumberString).get()));
*_retval = mBlocklist.Contains(issuerSerial);
@ -567,7 +573,9 @@ CertBlocklist::IsCertRevoked(const uint8_t* aIssuer,
return rv;
}
rv = crypto->Update(aPubKey, aPubKeyLength);
rv = crypto->Update(
BitwiseCast<const uint8_t*, const char*>(decodedPubKey.get()),
decodedPubKey.Length());
if (NS_FAILED(rv)) {
return rv;
}
@ -579,20 +587,24 @@ CertBlocklist::IsCertRevoked(const uint8_t* aIssuer,
}
CertBlocklistItem subjectPubKey(
aSubject,
static_cast<size_t>(aSubjectLength),
BitwiseCast<const uint8_t*, const char*>(decodedSubject.get()),
decodedSubject.Length(),
BitwiseCast<const uint8_t*, const char*>(hashString.get()),
hashString.Length(),
BlockBySubjectAndPubKey);
rv = subjectPubKey.ToBase64(encDN, encOther);
nsCString encodedHash;
rv = Base64Encode(hashString, encodedHash);
if (NS_FAILED(rv)) {
return rv;
}
MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
("CertBlocklist::IsCertRevoked subject %s - pubKey hash %s",
encDN.get(), encOther.get()));
MOZ_LOG(gCertBlockPRLog,
LogLevel::Warning,
("CertBlocklist::IsCertRevoked subject %s - pubKeyHash %s (pubKey %s)",
PromiseFlatCString(aSubjectString).get(),
PromiseFlatCString(encodedHash).get(),
PromiseFlatCString(aPubKeyString).get()));
*_retval = mBlocklist.Contains(subjectPubKey);
MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,

Просмотреть файл

@ -42,20 +42,16 @@ interface nsICertBlocklist : nsISupports {
/**
* Check if a certificate is blocked.
* issuer - issuer name, DER encoded
* serial - serial number, DER encoded
* subject - subject name, DER encoded
* pubkey - public key, DER encoded
* issuer - issuer name, DER, Base64 encoded
* serial - serial number, DER, BAse64 encoded
* subject - subject name, DER, Base64 encoded
* pubkey - public key, DER, Base64 encoded
*/
[must_use]
boolean isCertRevoked([const, array, size_is(issuer_length)] in octet issuer,
in unsigned long issuer_length,
[const, array, size_is(serial_length)] in octet serial,
in unsigned long serial_length,
[const, array, size_is(subject_length)] in octet subject,
in unsigned long subject_length,
[const, array, size_is(pubkey_length)] in octet pubkey,
in unsigned long pubkey_length);
boolean isCertRevoked(in ACString issuer,
in ACString serial,
in ACString subject,
in ACString pubkey);
/**
* Check that the blocklist data is current. Specifically, that the current

Просмотреть файл

@ -32,29 +32,27 @@ NS_IMPL_ISUPPORTS(nsSecureBrowserUIImpl,
nsISupportsWeakReference)
NS_IMETHODIMP
nsSecureBrowserUIImpl::Init(mozIDOMWindowProxy* aWindow)
nsSecureBrowserUIImpl::Init(nsIDocShell* aDocShell)
{
MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_ARG(aWindow);
NS_ENSURE_ARG(aDocShell);
auto* piwindow = nsPIDOMWindowOuter::From(aWindow);
nsIDocShell* docShell = piwindow->GetDocShell();
aDocShell->SetSecurityUI(this);
// The Docshell will own the SecureBrowserUI object
if (!docShell) {
return NS_ERROR_FAILURE;
// The Docshell will own the SecureBrowserUI object, we keep a weak ref.
nsresult rv;
mDocShell = do_GetWeakReference(aDocShell, &rv);
if (NS_FAILED(rv)) {
return rv;
}
docShell->SetSecurityUI(this);
// hook up to the webprogress notifications.
nsCOMPtr<nsIWebProgress> wp(do_GetInterface(docShell));
nsCOMPtr<nsIWebProgress> wp(do_GetInterface(aDocShell));
if (!wp) {
return NS_ERROR_FAILURE;
}
// Save this so we can compare it to the web progress in OnLocationChange.
nsresult rv;
mWebProgress = do_GetWeakReference(wp, &rv);
if (NS_FAILED(rv)) {
return rv;
@ -92,16 +90,6 @@ nsSecureBrowserUIImpl::GetSecInfo(nsITransportSecurityInfo** result)
return NS_OK;
}
NS_IMETHODIMP
nsSecureBrowserUIImpl::SetDocShell(nsIDocShell* aDocShell)
{
MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_ARG(aDocShell);
nsresult rv;
mDocShell = do_GetWeakReference(aDocShell, &rv);
return rv;
}
// Ask the docShell if we've blocked or loaded any mixed or tracking content.
void
nsSecureBrowserUIImpl::CheckForBlockedContent()

Просмотреть файл

@ -162,10 +162,6 @@ var addonManager = Cc["@mozilla.org/addons/integration;1"]
.QueryInterface(Ci.nsITimerCallback);
addonManager.observe(null, "addons-startup", null);
var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
function verify_cert(file, expectedError) {
let ee = constructCertFromFile(file);
return checkCertErrorGeneric(certDB, ee, expectedError,
@ -190,19 +186,8 @@ function load_cert(cert, trust) {
function test_is_revoked(certList, issuerString, serialString, subjectString,
pubKeyString) {
let issuer = converter.convertToByteArray(issuerString || "", {});
let serial = converter.convertToByteArray(serialString || "", {});
let subject = converter.convertToByteArray(subjectString || "", {});
let pubKey = converter.convertToByteArray(pubKeyString || "", {});
return certList.isCertRevoked(issuer,
issuerString ? issuerString.length : 0,
serial,
serialString ? serialString.length : 0,
subject,
subjectString ? subjectString.length : 0,
pubKey,
pubKeyString ? pubKeyString.length : 0);
return certList.isCertRevoked(btoa(issuerString), btoa(serialString),
btoa(subjectString), btoa(pubKeyString));
}
function fetch_blocklist() {

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше