Update On Tue Apr 1 20:55:44 CEST 2025

This commit is contained in:
github-action[bot] 2025-04-01 20:55:45 +02:00
parent 7fd5129ae4
commit c2daad41dd
553 changed files with 18696 additions and 10865 deletions

View file

@ -351,11 +351,11 @@ void LazyInstantiator::TransplantRefCnt() {
HRESULT
LazyInstantiator::MaybeResolveRoot() {
if (mWeakAccessible) {
return S_OK;
if (!GetAccService() && !ShouldInstantiate()) {
return E_FAIL;
}
if (GetAccService() || ShouldInstantiate()) {
if (!mWeakAccessible) {
mWeakMsaaRoot = ResolveMsaaRoot();
if (!mWeakMsaaRoot) {
return E_POINTER;
@ -372,7 +372,7 @@ LazyInstantiator::MaybeResolveRoot() {
TransplantRefCnt();
// Now obtain mWeakAccessible which we use to forward our incoming calls
// to the real accesssible.
// to the real accessible.
HRESULT hr =
mRealRootUnk->QueryInterface(IID_IAccessible, (void**)&mWeakAccessible);
if (FAILED(hr)) {
@ -380,23 +380,26 @@ LazyInstantiator::MaybeResolveRoot() {
}
// mWeakAccessible is weak, so don't hold a strong ref
mWeakAccessible->Release();
if (Compatibility::IsUiaEnabled()) {
hr = mRealRootUnk->QueryInterface(IID_IRawElementProviderSimple,
(void**)&mWeakUia);
if (FAILED(hr)) {
return hr;
}
mWeakUia->Release();
}
// Now that a11y is running, we don't need to remain registered with our
// HWND anymore.
ClearProp();
return S_OK;
}
return E_FAIL;
// If the UIA pref is changed during the session, this method might be first
// called with UIA disabled and then called again later with UIA enabled.
// Thus, we handle mWeakUia separately from mWeakAccessible.
if (!mWeakUia && Compatibility::IsUiaEnabled()) {
MOZ_ASSERT(mWeakAccessible);
HRESULT hr = mRealRootUnk->QueryInterface(IID_IRawElementProviderSimple,
(void**)&mWeakUia);
if (FAILED(hr)) {
return hr;
}
mWeakUia->Release();
}
return S_OK;
}
#define RESOLVE_ROOT \

View file

@ -2131,6 +2131,7 @@ pref("browser.ml.chat.sidebar", true);
pref("browser.ml.linkPreview.allowedLanguages", "en");
pref("browser.ml.linkPreview.enabled", false);
pref("browser.ml.linkPreview.outputSentences", 3);
pref("browser.ml.linkPreview.blockListEnabled", true);
// Block insecure active content on https pages
pref("security.mixed_content.block_active_content", true);

View file

@ -13,6 +13,7 @@
customtitlebar="true"
>
<head>
<meta http-equiv="Content-Security-Policy" content="default-src chrome:" />
<link rel="stylesheet" href="chrome://global/skin/global.css" />
<link rel="stylesheet" href="chrome://browser/skin/webRTC-indicator.css" />

View file

@ -1874,7 +1874,9 @@ BrowserGlue.prototype = {
Glean.startup.isCold.set(isColdStartup);
Glean.startup.secondsSinceLastOsRestart.set(secondsSinceLastOSRestart);
} catch (ex) {
console.error(ex);
if (ex.name !== "NS_ERROR_NOT_IMPLEMENTED") {
console.error(ex);
}
}
},

View file

@ -60,12 +60,6 @@ fail-if = ["a11y_checks"] # Bug 1850591 clicked moz-page-nav-button button is no
["browser_syncedtabs_errors_firefoxview.js"]
["browser_syncedtabs_firefoxview.js"]
skip-if = [
"os == 'linux' && os_version == '18.04' && processor == 'x86_64'", # Bug 1875321
"os == 'mac' && os_version == '11.20' && arch == 'aarch64' && opt", # Bug 1875321
"os == 'mac' && os_version == '10.15' && processor == 'x86_64' && opt", # Bug 1875321
"os == 'win' && os_version == '11.26100' && processor == 'x86_64' && opt", # Bug 1875321
]
["browser_tab_close_last_tab.js"]

View file

@ -112,8 +112,13 @@ add_task(async function test_signed_in() {
let connectAdditionalDevicesLink =
emptyState?.shadowRoot.querySelector("a");
connectAdditionalDevicesLink.scrollIntoView();
await TestUtils.waitForCondition(
() => BrowserTestUtils.isVisible(connectAdditionalDevicesLink),
await BrowserTestUtils.waitForMutationCondition(
emptyState.shadowRoot,
{ subTree: true, childList: true },
() => BrowserTestUtils.isVisible(connectAdditionalDevicesLink)
);
ok(
BrowserTestUtils.isVisible(connectAdditionalDevicesLink),
"Support url is visible"
);
is(

View file

@ -15,6 +15,8 @@ const CONTEXT_SIZE_MULTIPLIER = 0.69;
const DEFAULT_INPUT_SENTENCES = 6;
const MIN_SENTENCE_LENGTH = 14;
const MIN_WORD_COUNT = 5;
const DEFAULT_INPUT_PROMPT =
"Provide a concise, objective summary of the input text in up to three sentences, focusing on key actions and intentions without using second or third person pronouns.";
// All tokens taken from the model's vocabulary at https://huggingface.co/HuggingFaceTB/SmolLM2-360M-Instruct/raw/main/vocab.json
// Token id for end of text
@ -28,6 +30,8 @@ const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
createEngine: "chrome://global/content/ml/EngineProcess.sys.mjs",
Progress: "chrome://global/content/ml/Utils.sys.mjs",
BlockListManager: "chrome://global/content/ml/Utils.sys.mjs",
RemoteSettingsManager: "chrome://global/content/ml/Utils.sys.mjs",
});
XPCOMUtils.defineLazyPreferenceGetter(
lazy,
@ -38,8 +42,7 @@ XPCOMUtils.defineLazyPreferenceGetter(
XPCOMUtils.defineLazyPreferenceGetter(
lazy,
"inputSentences",
"browser.ml.linkPreview.inputSentences",
DEFAULT_INPUT_SENTENCES
"browser.ml.linkPreview.inputSentences"
);
XPCOMUtils.defineLazyPreferenceGetter(
lazy,
@ -49,11 +52,22 @@ XPCOMUtils.defineLazyPreferenceGetter(
XPCOMUtils.defineLazyPreferenceGetter(
lazy,
"prompt",
"browser.ml.linkPreview.prompt",
"Provide a concise, objective summary of the input text in up to three sentences, focusing on key actions and intentions without using second or third person pronouns."
"browser.ml.linkPreview.prompt"
);
XPCOMUtils.defineLazyPreferenceGetter(
lazy,
"blockListEnabled",
"browser.ml.linkPreview.blockListEnabled"
);
export const LinkPreviewModel = {
/**
* Manager for the block list. If null, no block list is applied.
*
* @type {BlockListManager}
*/
blockListManager: null,
/**
* Blocked token list
*
@ -228,9 +242,13 @@ export const LinkPreviewModel = {
* Clean up text for text generation AI.
*
* @param {string} text to process
* @param {number} maxNumSentences - Max number of sentences to return.
* @returns {string} cleaned up text
*/
preprocessText(text) {
preprocessText(
text,
maxNumSentences = lazy.inputSentences ?? DEFAULT_INPUT_SENTENCES
) {
return (
this.getSentences(text)
.map(s =>
@ -256,11 +274,22 @@ export const LinkPreviewModel = {
s.split(" ").length >= MIN_WORD_COUNT &&
/\p{P}$/u.test(s)
)
.slice(0, lazy.inputSentences)
.slice(0, maxNumSentences)
.join(" ")
);
},
/**
* Creates a new ML engine instance with the provided options for link preview.
*
* @param {object} options - Configuration options for the ML engine.
* @param {?function(ProgressAndStatusCallbackParams):void} notificationsCallback A function to call to indicate notifications.
* @returns {Promise<MLEngine>} - A promise that resolves to the ML engine instance.
*/
async createEngine(options, notificationsCallback = null) {
return lazy.createEngine(options, notificationsCallback);
},
/**
* Generate summary text using AI.
*
@ -271,10 +300,43 @@ export const LinkPreviewModel = {
* @param {Function} callbacks.onError optional for error
*/
async generateTextAI(inputText, { onDownload, onText, onError } = {}) {
const processedInput = this.preprocessText(inputText);
// Get updated options from remote settings. No failure if no record exists
const remoteRequestRecord = await lazy.RemoteSettingsManager.getRemoteData({
collectionName: "ml-inference-request-options",
filters: { featureId: "link-preview" },
majorVersion: 1,
}).catch(() => {
console.error(
"Error retrieving request options from remote settings, will use default options."
);
return { options: "{}" };
});
let remoteRequestOptions = {};
try {
remoteRequestOptions = remoteRequestRecord?.options
? JSON.parse(remoteRequestRecord.options)
: {};
} catch (error) {
console.error(
"Error parsing the remote settings request options, will use default options.",
error
);
}
// TODO: Unit test that order of preference is correctly respected.
const processedInput = this.preprocessText(
inputText,
lazy.inputSentences ??
remoteRequestOptions?.inputSentences ??
DEFAULT_INPUT_SENTENCES
);
// Asssume generated text is approximately the same length as the input.
const nPredict = Math.ceil(processedInput.length / CHARACTERS_PER_TOKEN);
const systemPrompt = lazy.prompt;
const systemPrompt =
lazy.prompt ?? remoteRequestOptions?.systemPrompt ?? DEFAULT_INPUT_PROMPT;
// Estimate an upper bound for the required number of tokens. This estimate
// must be large enough to include prompt tokens, input tokens, and
// generated tokens.
@ -285,7 +347,7 @@ export const LinkPreviewModel = {
let engine;
try {
engine = await lazy.createEngine(
engine = await this.createEngine(
{
backend: "wllama",
engineId: "wllamapreview",
@ -315,7 +377,7 @@ export const LinkPreviewModel = {
}
);
const postProcessor = new SentencePostProcessor();
const postProcessor = await SentencePostProcessor.initialize();
const blockedTokens = this.getBlockTokenList();
for await (const val of engine.runWithGenerator({
nPredict,
@ -380,11 +442,56 @@ export class SentencePostProcessor {
currentNumSentences = 0;
/**
* @param {number} maxNumOutputSentences - The maximum number of sentences to
* output before truncating the buffer.
* Manager for the block list. If null, no block list is applied.
*
* @type {BlockListManager}
*/
constructor(maxNumOutputSentences = lazy.outputSentences) {
blockListManager = null;
/**
* Create an instance of the sentence postprocessor.
*
* @param {object} config - Configuration object.
* @param {number} config.maxNumOutputSentences - The maximum number of sentences to
* output before truncating the buffer.
* @param {BlockListManager | null} config.blockListManager - Manager for the block list
*/
constructor({
maxNumOutputSentences = lazy.outputSentences,
blockListManager,
} = {}) {
this.maxNumOutputSentences = maxNumOutputSentences;
this.blockListManager = blockListManager;
}
/**
* @param {object} config - Configuration object.
* @param {number} config.maxNumOutputSentences - The maximum number of sentences to
* output before truncating the buffer.
* @param {boolean} config.blockListEnabled - Wether to enable block list. If enabled, we
* don't return the sentence that has a blocked word along with any sentences coming after.
* @returns {SentencePostProcessor} - An instance of SentencePostProcessor
*/
static async initialize({
maxNumOutputSentences = lazy.outputSentences,
blockListEnabled = lazy.blockListEnabled,
} = {}) {
if (!blockListEnabled) {
LinkPreviewModel.blockListManager = null;
} else if (!LinkPreviewModel.blockListManager) {
LinkPreviewModel.blockListManager =
await lazy.BlockListManager.initializeFromRemoteSettings({
blockListName: "link-preview-test-en",
language: "en",
fallbackToDefault: true,
majorVersion: 1,
});
}
return new SentencePostProcessor({
maxNumOutputSentences,
blockListManager: LinkPreviewModel.blockListManager,
});
}
/**
@ -417,6 +524,16 @@ export class SentencePostProcessor {
abort = true;
}
sentence = sentences[0];
// If the sentence contains a block word, abort
if (
this.blockListManager &&
this.blockListManager.matchAtWordBoundary({ text: sentence })
) {
sentence = "";
abort = true;
this.currentNumSentences = this.maxNumOutputSentences;
}
}
return { sentence, abort };

View file

@ -43,6 +43,11 @@
-webkit-line-clamp: 3;
}
.og-error-message {
font-size: var(--og-main-font-size);
margin-block: 0 var(--space-medium);
}
.ai-content {
padding: var(--og-padding);

View file

@ -13,8 +13,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
});
// TODO put in actual link probably same as labs bug 1951144
const FEEDBACK_LINK =
"https://docs.google.com/spreadsheets/d/1hsG7UXGJRN8D4ViaETICDyA0gbBArzmib1qTylmIu8M";
const FEEDBACK_LINK = "https://connect.mozilla.org/";
/**
* Class representing a link preview element.
@ -22,6 +21,11 @@ const FEEDBACK_LINK =
* @augments MozLitElement
*/
class LinkPreviewCard extends MozLitElement {
// Error message to display when we can't generate a preview
static ERROR_CARD_MESSAGE = "We can't preview this link";
// Text for the link to visit the original URL when in error state
static VISIT_LINK_TEXT = "Visit link";
static properties = {
generating: { type: Number }, // 0 = off, 1-4 = generating & dots state
keyPoints: { type: Array },
@ -80,6 +84,41 @@ class LinkPreviewCard extends MozLitElement {
}
}
/**
* Extracts and validates essential metadata for link preview.
*
* This utility function processes the metadata object to extract the title and
* description from various potential sources (Open Graph, Twitter, HTML).
* It also determines if there's sufficient metadata to generate a meaningful preview.
*
* @param {object} metaData - The metadata object containing page information
* @returns {object} An object containing:
* - isMissingMetadata {boolean} - True if either title or description is missing
* - title {string} - The extracted page title or empty string if none found
* - description {string} - The extracted page description or empty string if none found
*/
extractMetadataContent(metaData = {}) {
const title =
metaData["og:title"] ||
metaData["twitter:title"] ||
metaData["html:title"] ||
"";
const description =
metaData["og:description"] ||
metaData["twitter:description"] ||
metaData.description ||
"";
const isMissingMetadata = !title || !description;
return {
isMissingMetadata,
title,
description,
};
}
/**
* Renders the link preview element.
*
@ -89,21 +128,10 @@ class LinkPreviewCard extends MozLitElement {
const articleData = this.pageData?.article || {};
const metaData = this.pageData?.metaInfo || {};
const pageUrl = this.pageData?.url || "about:blank";
const siteName = articleData.siteName || "";
const title =
metaData["og:title"] ||
metaData["twitter:title"] ||
metaData["html:title"] ||
"This link cant be previewed";
const description =
articleData.excerpt ||
metaData["og:description"] ||
metaData["twitter:description"] ||
metaData.description ||
"No Reason. Just cause. (better error handling incoming)";
const { isMissingMetadata, title, description } =
this.extractMetadataContent(metaData);
let imageUrl = metaData["og:image"] || metaData["twitter:image:src"] || "";
if (!imageUrl.startsWith("https://")) {
@ -118,11 +146,28 @@ class LinkPreviewCard extends MozLitElement {
displayProgressPercentage = 100;
}
return html`
<link
rel="stylesheet"
href="chrome://browser/content/genai/content/link-preview-card.css"
/>
// Error Link Preview card UI: A simplified version of the preview card showing only an error message
// and a link to visit the URL. This is a fallback UI for cases when we don't have
// enough metadata to generate a useful preview.
const errorCard = html`
<div class="og-card">
<div class="og-card-content">
<div class="og-error-content">
<p class="og-error-message">
${LinkPreviewCard.ERROR_CARD_MESSAGE}
</p>
<a class="og-card-title" @click=${this.handleLink} href=${pageUrl}>
${LinkPreviewCard.VISIT_LINK_TEXT}
</a>
</div>
</div>
</div>
`;
// Normal Link Preview card UI: Shown when we have sufficient metadata (at least title and description)
// Displays rich preview information including optional elements like site name, image,
// reading time, and AI-generated key points if available
const normalCard = html`
<div class="og-card">
<div class="og-card-content">
${imageUrl
@ -195,6 +240,14 @@ class LinkPreviewCard extends MozLitElement {
: ""}
</div>
`;
return html`
<link
rel="stylesheet"
href="chrome://browser/content/genai/content/link-preview-card.css"
/>
${isMissingMetadata ? errorCard : normalCard}
`;
}
}

View file

@ -8,6 +8,14 @@ const { SentencePostProcessor } = ChromeUtils.importESModule(
"moz-src:///browser/components/genai/LinkPreviewModel.sys.mjs"
);
const { sinon } = ChromeUtils.importESModule(
"resource://testing-common/Sinon.sys.mjs"
);
const { BlockListManager } = ChromeUtils.importESModule(
"chrome://global/content/ml/Utils.sys.mjs"
);
/**
* Test that text is processed for ai.
*/
@ -123,11 +131,145 @@ add_task(function test_sentence_post_processor() {
Assert.equal(processor.flush(), "", "still nothing at limit");
});
/**
* Test that generateTextAI works properly with the blocklist
*/
add_task(async function test_generateAI_with_blocklist() {
// Mocked ML Engine
const engine = {
async *runWithGenerator() {
const preview =
"Hello world, I am here and would like to make a sentence. Now, more sentences are coming. Even more are raining here. Bye";
for (const text of preview) {
yield { text };
}
},
terminate() {},
};
// Mocked Blocked List Manager
let manager = new BlockListManager({
blockNgrams: [BlockListManager.encodeBase64("Hello")],
language: "en",
});
// Disable block list
Services.prefs.setBoolPref("browser.ml.linkPreview.blockListEnabled", false);
let createEngineStub = sinon
.stub(LinkPreviewModel, "createEngine")
.returns(engine);
let managerStub = sinon
.stub(BlockListManager, "initializeFromRemoteSettings")
.returns(manager);
let numOutputs = 0;
await LinkPreviewModel.generateTextAI(
"This is the big article. Now give me its preview. Please.",
{
onText: () => {
numOutputs += 1;
},
}
);
Assert.equal(
numOutputs,
3,
"should output all sentences when block list is disabled"
);
// Enable block list
Services.prefs.setBoolPref("browser.ml.linkPreview.blockListEnabled", true);
numOutputs = 0;
await LinkPreviewModel.generateTextAI(
"This is the big article. Now give me its preview. Please.",
{
onText: () => {
numOutputs += 1;
},
}
);
Assert.equal(
numOutputs,
0,
"Should output no sentences when 1st sentence contains block word and block list enabled."
);
managerStub.restore();
manager = new BlockListManager({
blockNgrams: [BlockListManager.encodeBase64("coming")],
language: "en",
});
managerStub = sinon
.stub(BlockListManager, "initializeFromRemoteSettings")
.returns(manager);
// Force link preview to reload blockList manager
Services.prefs.setBoolPref("browser.ml.linkPreview.blockListEnabled", false);
await LinkPreviewModel.generateTextAI(
"This is the big article. Now give me its preview. Please."
);
Assert.equal(LinkPreviewModel.blockListManager, null);
// Now re-enable block list
Services.prefs.setBoolPref("browser.ml.linkPreview.blockListEnabled", true);
numOutputs = 0;
await LinkPreviewModel.generateTextAI(
"This is the big article. Now give me its preview. Please.",
{
onText: () => {
numOutputs += 1;
},
}
);
Assert.equal(
numOutputs,
1,
"Should output 1 sentence when blocked word found 1st time in 2nd sentence and block list enabled."
);
Services.prefs.setBoolPref("browser.ml.linkPreview.blockListEnabled", false);
numOutputs = 0;
await LinkPreviewModel.generateTextAI(
"This is the big article. Now give me its preview. Please.",
{
onText: () => {
numOutputs += 1;
},
}
);
Assert.equal(
numOutputs,
3,
"all sentences should be outputted when block list disabled"
);
Services.prefs.clearUserPref("browser.ml.linkPreview.blockListEnabled");
createEngineStub.restore();
managerStub.restore();
});
/**
* Test post processor respects limits.
*/
add_task(function test_sentence_post_processor_limits() {
const processor = new SentencePostProcessor(1);
const processor = new SentencePostProcessor({
maxNumOutputSentences: 1,
});
Assert.deepEqual(
processor.put("Hi. There. "),
{ sentence: "Hi. ", abort: true },

View file

@ -68,32 +68,16 @@ class BrowserSearchTelemetryHandler {
}
/**
* Records the method by which the user selected a result from the urlbar or
* searchbar.
* Records the method by which the user selected a result from the searchbar.
*
* @param {Event} event
* The event that triggered the selection.
* @param {string} source
* Either "urlbar" or "searchbar" depending on the source.
* @param {number} index
* The index that the user chose in the popup, or -1 if there wasn't a
* selection.
* @param {string} userSelectionBehavior
* How the user cycled through results before picking the current match.
* Could be one of "tab", "arrow" or "none".
*/
recordSearchSuggestionSelectionMethod(
event,
source,
index,
userSelectionBehavior = "none"
) {
// If the contents of the histogram are changed then
// `UrlbarTestUtils.SELECTED_RESULT_METHODS` should also be updated.
if (source == "searchbar" && userSelectionBehavior != "none") {
throw new Error("Did not expect a selection behavior for the searchbar.");
}
// command events are from the one-off context menu. Treat them as clicks.
recordSearchSuggestionSelectionMethod(event, index) {
// command events are from the one-off context menu. Treat them as clicks.
// Note that we only care about MouseEvent subclasses here when the
// event type is "click", or else the subclasses are associated with
// non-click interactions.
@ -106,26 +90,12 @@ class BrowserSearchTelemetryHandler {
if (isClick) {
category = "click";
} else if (index >= 0) {
switch (userSelectionBehavior) {
case "tab":
category = "tabEnterSelection";
break;
case "arrow":
category = "arrowEnterSelection";
break;
case "rightClick":
// Selected by right mouse button.
category = "rightClickEnter";
break;
default:
category = "enterSelection";
}
category = "enterSelection";
} else {
category = "enter";
}
if (source == "searchbar") {
Glean.searchbar.selectedResultMethod[category].add(1);
}
Glean.searchbar.selectedResultMethod[category].add(1);
}
/**

View file

@ -193,7 +193,6 @@
// Check for middle-click or modified clicks on the search bar
BrowserSearchTelemetry.recordSearchSuggestionSelectionMethod(
aEvent,
"searchbar",
this.selectedIndex
);

View file

@ -332,7 +332,6 @@
lazy.BrowserSearchTelemetry.recordSearchSuggestionSelectionMethod(
aEvent,
"searchbar",
selectedIndex
);

View file

@ -2132,14 +2132,12 @@ XPCOMUtils.defineLazyPreferenceGetter(
"sidebarRevampVisibility",
"sidebar.visibility",
"always-show",
async (_aPreference, _previousValue, newValue) => {
(_aPreference, _previousValue, newValue) => {
if (
!SidebarController.inSingleTabWindow &&
!SidebarController.uninitializing
) {
await SidebarController.toggleExpandOnHover(
newValue === "expand-on-hover"
);
SidebarController.toggleExpandOnHover(newValue === "expand-on-hover");
SidebarController.recordVisibilitySetting(newValue);
if (SidebarController._state) {
// we need to use the pref rather than SidebarController's getter here

View file

@ -116,7 +116,8 @@ add_task(async function test_enable_expand_on_hover() {
!SidebarController._state.launcherExpanded &&
SidebarController.sidebarRevampVisibility === "expand-on-hover" &&
window.getComputedStyle(SidebarController.sidebarContainer).position ===
"relative",
"relative" &&
panel.expandOnHoverInput.checked,
"Expand on hover has been enabled"
);
@ -154,8 +155,18 @@ add_task(async function test_enable_expand_on_hover() {
);
await mouseOutSidebarToCollapse();
await SidebarController.toggleExpandOnHover(false);
await SidebarController.waitUntilStable();
panel.expandOnHoverInput.click();
await BrowserTestUtils.waitForMutationCondition(
SidebarController.sidebarContainer,
{ attributes: true },
() =>
!rootEl.hasAttribute("sidebar-expand-on-hover") &&
SidebarController.sidebarRevampVisibility !== "expand-on-hover" &&
window.getComputedStyle(SidebarController.sidebarContainer).position !==
"relative" &&
!panel.expandOnHoverInput.checked,
"Expand on hover has been disabled"
);
});
add_task(async function test_expand_on_hover_pinned_tabs() {

View file

@ -56,6 +56,7 @@ export const DIM_REDUCTION_METHODS = {};
const MISSING_ANCHOR_IN_CLUSTER_PENALTY = 0.2;
const NEAREST_NEIGHBOR_DEFAULT_THRESHOLD = 0.21;
const MAX_NN_GROUPED_TABS = 4;
const MAX_SUGGESTED_TABS = 10;
const DISSIMILAR_TAB_LABEL = "none";
const ADULT_TAB_LABEL = "adult content";
@ -204,7 +205,7 @@ export class SmartTabGroupingManager {
groupLabel: group?.label,
});
}
return suggestedTabs;
return suggestedTabs.slice(0, MAX_SUGGESTED_TABS);
}
/**

View file

@ -53,12 +53,6 @@ known_errors = [
# Bug 1936426 to reconsider warning as we want ctrl-alt-x for chatbot.
"message": "viewGenaiChatSidebarKb",
},
{
# Triggered on Linux because it doesn't implement the
# secondsSinceLastOSRestart property at all.
"message": "(NS_ERROR_NOT_IMPLEMENTED) [nsIAppStartup.secondsSinceLastOSRestart]",
"filename": "BrowserGlue",
},
{
# Triggered as soon as anything tries to use shortcut keys.
# Bug 1936426 to reconsider warning as we want ctrl-z / ctrl-alt-z

View file

@ -7,8 +7,6 @@ import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
BrowserSearchTelemetry:
"moz-src:///browser/components/search/BrowserSearchTelemetry.sys.mjs",
UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
UrlbarProvidersManager: "resource:///modules/UrlbarProvidersManager.sys.mjs",
UrlbarTokenizer: "resource:///modules/UrlbarTokenizer.sys.mjs",
@ -601,32 +599,6 @@ export class UrlbarController {
this._userSelectionBehavior = behavior;
}
/**
* Records details of the selected result in telemetry. We only record the
* selection behavior, type and index.
*
* @param {Event} event
* The event which triggered the result to be selected.
* @param {UrlbarResult} result
* The selected result.
*/
recordSelectedResult(event, result) {
let resultIndex = result ? result.rowIndex : -1;
let selectedResult = -1;
if (resultIndex >= 0) {
// Except for the history popup, the urlbar always has a selection. The
// first result at index 0 is the "heuristic" result that indicates what
// will happen when you press the Enter key. Treat it as no selection.
selectedResult = resultIndex > 0 || !result.heuristic ? resultIndex : -1;
}
lazy.BrowserSearchTelemetry.recordSearchSuggestionSelectionMethod(
event,
"urlbar",
selectedResult,
this._userSelectionBehavior
);
}
/**
* Triggers a "dismiss" engagement for the selected result if one is selected
* and it's not the heuristic. Providers that can respond to dismissals of

View file

@ -837,9 +837,6 @@ export class UrlbarInput {
return;
}
let selectedResult = result || this.view.selectedResult;
this.controller.recordSelectedResult(event, selectedResult);
let where = oneOffParams?.openWhere || this._whereToOpen(event);
if (selectedPrivateResult) {
where = "window";
@ -848,6 +845,7 @@ export class UrlbarInput {
openParams.allowInheritPrincipal = false;
url = this._maybeCanonizeURL(event, url) || url.trim();
let selectedResult = result || this.view.selectedResult;
this.controller.engagementEvent.record(event, {
element,
selType,
@ -1096,8 +1094,6 @@ export class UrlbarInput {
this.view.close({ elementPicked: true });
}
this.controller.recordSelectedResult(event, result);
if (isCanonized) {
this.controller.engagementEvent.record(event, {
result,

View file

@ -5,9 +5,18 @@
const { UrlbarSearchUtils } = ChromeUtils.importESModule(
"resource:///modules/UrlbarSearchUtils.sys.mjs"
);
const { updateAppInfo } = ChromeUtils.importESModule(
"resource://testing-common/AppInfo.sys.mjs"
);
let baconEngineExtension;
add_setup(async function () {
updateAppInfo({
name: "firefox",
});
});
add_task(async function () {
await UrlbarSearchUtils.init();
// Tell the search service we are running in the US. This also has the
@ -61,15 +70,18 @@ add_task(async function hide_search_engine_nomatch() {
});
add_task(async function onlyEnabled_option_nomatch() {
let engine = await Services.search.getDefault();
let domain = engine.searchUrlDomain;
let defaultEngine = await Services.search.getDefault();
let domain = defaultEngine.searchUrlDomain;
let token = domain.substr(0, 1);
engine.hideOneOffButton = true;
defaultEngine.hideOneOffButton = true;
let matchedEngines = await UrlbarSearchUtils.enginesForDomainPrefix(token);
Assert.equal(matchedEngines.length, 0);
engine.hideOneOffButton = false;
Assert.notEqual(matchedEngines[0], defaultEngine);
defaultEngine.hideOneOffButton = false;
matchedEngines = await UrlbarSearchUtils.enginesForDomainPrefix(token);
Assert.equal(matchedEngines[0].searchUrlDomain, domain);
Assert.equal(matchedEngines[0], defaultEngine);
});
add_task(async function add_search_engine_match() {

View file

@ -179,6 +179,36 @@ export class BaseContent extends React.PureComponent {
this.handleColorModeChange
);
this.handleColorModeChange();
this.updateWallpaper();
}
componentDidUpdate(prevProps) {
// destructure current and previous props with fallbacks
// (preventing undefined errors)
const {
Wallpapers: { uploadedWallpaper = null, wallpaperList = null } = {},
Prefs: { values: currentPrefs = {} } = {},
} = this.props;
const {
Wallpapers: {
uploadedWallpaper: prevUploadedWallpaper = null,
wallpaperList: prevWallpaperList = null,
} = {},
Prefs: { values: prevPrefs = {} } = {},
} = prevProps;
const selectedWallpaper = currentPrefs["newtabWallpapers.wallpaper"];
const prevSelectedWallpaper = prevPrefs["newtabWallpapers.wallpaper"];
// don't update wallpaper unless the wallpaper is being changed.
if (
selectedWallpaper !== prevSelectedWallpaper || // selecting a new wallpaper
uploadedWallpaper !== prevUploadedWallpaper || // uploading a new wallpaper
wallpaperList !== prevWallpaperList // remote settings wallpaper list updates
) {
this.updateWallpaper();
}
}
handleColorModeChange() {
@ -640,9 +670,6 @@ export class BaseContent extends React.PureComponent {
]
.filter(v => v)
.join(" ");
if (wallpapersV2Enabled) {
this.updateWallpaper();
}
return (
<div className={featureClassName}>

View file

@ -13731,6 +13731,41 @@ class BaseContent extends (external_React_default()).PureComponent {
this.prefersDarkQuery = globalThis.matchMedia("(prefers-color-scheme: dark)");
this.prefersDarkQuery.addEventListener("change", this.handleColorModeChange);
this.handleColorModeChange();
this.updateWallpaper();
}
componentDidUpdate(prevProps) {
// destructure current and previous props with fallbacks
// (preventing undefined errors)
const {
Wallpapers: {
uploadedWallpaper = null,
wallpaperList = null
} = {},
Prefs: {
values: currentPrefs = {}
} = {}
} = this.props;
const {
Wallpapers: {
uploadedWallpaper: prevUploadedWallpaper = null,
wallpaperList: prevWallpaperList = null
} = {},
Prefs: {
values: prevPrefs = {}
} = {}
} = prevProps;
const selectedWallpaper = currentPrefs["newtabWallpapers.wallpaper"];
const prevSelectedWallpaper = prevPrefs["newtabWallpapers.wallpaper"];
// don't update wallpaper unless the wallpaper is being changed.
if (selectedWallpaper !== prevSelectedWallpaper ||
// selecting a new wallpaper
uploadedWallpaper !== prevUploadedWallpaper ||
// uploading a new wallpaper
wallpaperList !== prevWallpaperList // remote settings wallpaper list updates
) {
this.updateWallpaper();
}
}
handleColorModeChange() {
const colorMode = this.prefersDarkQuery?.matches ? "dark" : "light";
@ -14101,9 +14136,6 @@ class BaseContent extends (external_React_default()).PureComponent {
// Shortcuts refresh experiment
pocketEnabled ? "has-recommended-stories" : "no-recommended-stories", sectionsEnabled ? "has-sections-grid" : ""].filter(v => v).join(" ");
const outerClassName = ["outer-wrapper", isDiscoveryStream && pocketEnabled && "ds-outer-wrapper-search-alignment", isDiscoveryStream && "ds-outer-wrapper-breakpoint-override", prefs.showSearch && this.state.fixedSearch && !noSectionsEnabled && "fixed-search", prefs.showSearch && noSectionsEnabled && "only-search", prefs["feeds.topsites"] && !pocketEnabled && !prefs.showSearch && "only-topsites", noSectionsEnabled && "no-sections", prefs["logowordmark.alwaysVisible"] && "visible-logo", hasThumbsUpDownLayout && hasThumbsUpDown && "thumbs-ui-compact"].filter(v => v).join(" ");
if (wallpapersV2Enabled) {
this.updateWallpaper();
}
return /*#__PURE__*/external_React_default().createElement("div", {
className: featureClassName
}, /*#__PURE__*/external_React_default().createElement("menu", {

View file

@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "New Tab",
"description": "",
"version": "138.0.0",
"version": "139.0.0",
"browser_specific_settings": {
"gecko": {

View file

@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "Web Compatibility Interventions",
"description": "Urgent post-release fixes for web compatibility.",
"version": "138.3.0",
"version": "139.0.0",
"browser_specific_settings": {
"gecko": {
"id": "webcompat@mozilla.org",

View file

@ -158,8 +158,6 @@ sidebar-menu-history-header =
.heading = History
sidebar-menu-syncedtabs-header =
.heading = Tabs from other devices
sidebar-menu-bookmarks-header =
.heading = Bookmarks
sidebar-menu-cpm-header =
.heading = Passwords

View file

@ -17,7 +17,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"af": {
"pin": false,
@ -37,7 +37,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"an": {
"pin": false,
@ -57,7 +57,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"ar": {
"pin": false,
@ -77,7 +77,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"ast": {
"pin": false,
@ -97,7 +97,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"az": {
"pin": false,
@ -117,7 +117,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"be": {
"pin": false,
@ -137,7 +137,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"bg": {
"pin": false,
@ -157,7 +157,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"bn": {
"pin": false,
@ -177,7 +177,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"bo": {
"pin": false,
@ -197,7 +197,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"br": {
"pin": false,
@ -217,7 +217,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"brx": {
"pin": false,
@ -237,7 +237,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"bs": {
"pin": false,
@ -257,7 +257,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"ca": {
"pin": false,
@ -277,7 +277,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"ca-valencia": {
"pin": false,
@ -297,7 +297,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"cak": {
"pin": false,
@ -317,7 +317,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"ckb": {
"pin": false,
@ -337,7 +337,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"cs": {
"pin": false,
@ -357,7 +357,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"cy": {
"pin": false,
@ -377,7 +377,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"da": {
"pin": false,
@ -397,7 +397,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"de": {
"pin": false,
@ -417,7 +417,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"dsb": {
"pin": false,
@ -437,7 +437,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"el": {
"pin": false,
@ -457,7 +457,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"en-CA": {
"pin": false,
@ -477,7 +477,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"en-GB": {
"pin": false,
@ -497,7 +497,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"eo": {
"pin": false,
@ -517,7 +517,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"es-AR": {
"pin": false,
@ -537,7 +537,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"es-CL": {
"pin": false,
@ -557,7 +557,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"es-ES": {
"pin": false,
@ -577,7 +577,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"es-MX": {
"pin": false,
@ -597,7 +597,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"et": {
"pin": false,
@ -617,7 +617,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"eu": {
"pin": false,
@ -637,7 +637,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"fa": {
"pin": false,
@ -657,7 +657,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"ff": {
"pin": false,
@ -677,7 +677,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"fi": {
"pin": false,
@ -697,7 +697,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"fr": {
"pin": false,
@ -717,7 +717,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"fur": {
"pin": false,
@ -737,7 +737,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"fy-NL": {
"pin": false,
@ -757,7 +757,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"ga-IE": {
"pin": false,
@ -777,7 +777,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"gd": {
"pin": false,
@ -797,7 +797,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"gl": {
"pin": false,
@ -817,7 +817,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"gn": {
"pin": false,
@ -837,7 +837,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"gu-IN": {
"pin": false,
@ -857,7 +857,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"he": {
"pin": false,
@ -877,7 +877,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"hi-IN": {
"pin": false,
@ -897,7 +897,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"hr": {
"pin": false,
@ -917,7 +917,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"hsb": {
"pin": false,
@ -937,7 +937,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"hu": {
"pin": false,
@ -957,7 +957,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"hy-AM": {
"pin": false,
@ -977,7 +977,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"hye": {
"pin": false,
@ -997,7 +997,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"ia": {
"pin": false,
@ -1017,7 +1017,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"id": {
"pin": false,
@ -1037,7 +1037,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"is": {
"pin": false,
@ -1057,7 +1057,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"it": {
"pin": false,
@ -1077,7 +1077,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"ja": {
"pin": false,
@ -1095,7 +1095,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"ja-JP-mac": {
"pin": false,
@ -1103,7 +1103,7 @@
"macosx64",
"macosx64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"ka": {
"pin": false,
@ -1123,7 +1123,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"kab": {
"pin": false,
@ -1143,7 +1143,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"kk": {
"pin": false,
@ -1163,7 +1163,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"km": {
"pin": false,
@ -1183,7 +1183,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"kn": {
"pin": false,
@ -1203,7 +1203,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"ko": {
"pin": false,
@ -1223,7 +1223,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"lij": {
"pin": false,
@ -1243,7 +1243,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"lo": {
"pin": false,
@ -1263,7 +1263,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"lt": {
"pin": false,
@ -1283,7 +1283,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"ltg": {
"pin": false,
@ -1303,7 +1303,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"lv": {
"pin": false,
@ -1323,7 +1323,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"meh": {
"pin": false,
@ -1343,7 +1343,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"mk": {
"pin": false,
@ -1363,7 +1363,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"ml": {
"pin": false,
@ -1383,7 +1383,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"mr": {
"pin": false,
@ -1403,7 +1403,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"ms": {
"pin": false,
@ -1423,7 +1423,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"my": {
"pin": false,
@ -1443,7 +1443,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"nb-NO": {
"pin": false,
@ -1463,7 +1463,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"ne-NP": {
"pin": false,
@ -1483,7 +1483,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"nl": {
"pin": false,
@ -1503,7 +1503,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"nn-NO": {
"pin": false,
@ -1523,7 +1523,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"oc": {
"pin": false,
@ -1543,7 +1543,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"pa-IN": {
"pin": false,
@ -1563,7 +1563,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"pl": {
"pin": false,
@ -1583,7 +1583,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"pt-BR": {
"pin": false,
@ -1603,7 +1603,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"pt-PT": {
"pin": false,
@ -1623,7 +1623,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"rm": {
"pin": false,
@ -1643,7 +1643,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"ro": {
"pin": false,
@ -1663,7 +1663,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"ru": {
"pin": false,
@ -1683,7 +1683,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"sat": {
"pin": false,
@ -1703,7 +1703,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"sc": {
"pin": false,
@ -1723,7 +1723,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"scn": {
"pin": false,
@ -1743,7 +1743,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"sco": {
"pin": false,
@ -1763,7 +1763,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"si": {
"pin": false,
@ -1783,7 +1783,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"sk": {
"pin": false,
@ -1803,7 +1803,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"skr": {
"pin": false,
@ -1823,7 +1823,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"sl": {
"pin": false,
@ -1843,7 +1843,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"son": {
"pin": false,
@ -1863,7 +1863,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"sq": {
"pin": false,
@ -1883,7 +1883,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"sr": {
"pin": false,
@ -1903,7 +1903,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"sv-SE": {
"pin": false,
@ -1923,7 +1923,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"szl": {
"pin": false,
@ -1943,7 +1943,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"ta": {
"pin": false,
@ -1963,7 +1963,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"te": {
"pin": false,
@ -1983,7 +1983,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"tg": {
"pin": false,
@ -2003,7 +2003,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"th": {
"pin": false,
@ -2023,7 +2023,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"tl": {
"pin": false,
@ -2043,7 +2043,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"tr": {
"pin": false,
@ -2063,7 +2063,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"trs": {
"pin": false,
@ -2083,7 +2083,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"uk": {
"pin": false,
@ -2103,7 +2103,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"ur": {
"pin": false,
@ -2123,7 +2123,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"uz": {
"pin": false,
@ -2143,7 +2143,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"vi": {
"pin": false,
@ -2163,7 +2163,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"wo": {
"pin": false,
@ -2183,7 +2183,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"xh": {
"pin": false,
@ -2203,7 +2203,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"zh-CN": {
"pin": false,
@ -2223,7 +2223,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
},
"zh-TW": {
"pin": false,
@ -2243,6 +2243,6 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "c573f636d5ffaae13760e004d497cc0d0139b75f"
"revision": "1f3a680b0d835e8a29dc7548b2e5717069f65ecd"
}
}

View file

@ -15,13 +15,6 @@
--menu-panel-width: 22.35em;
--menu-panel-width-wide: 29em;
--arrowpanel-menuitem-margin-block: 0;
--arrowpanel-menuitem-margin-inline: 8px;
--arrowpanel-menuitem-margin: var(--arrowpanel-menuitem-margin-block) var(--arrowpanel-menuitem-margin-inline);
--arrowpanel-menuitem-padding-block: 8px;
--arrowpanel-menuitem-padding-inline: 8px;
--arrowpanel-menuitem-padding: var(--arrowpanel-menuitem-padding-block) var(--arrowpanel-menuitem-padding-inline);
--arrowpanel-menuitem-border-radius: 4px;
--arrowpanel-header-info-icon-padding: 4px;
--arrowpanel-header-info-icon-full-width: calc(16px + (2 * var(--arrowpanel-header-info-icon-padding)));
--panel-separator-margin-vertical: 4px;
@ -311,6 +304,9 @@ panelview {
--panel-border-radius: var(--arrowpanel-border-radius);
--panel-padding: var(--panel-subview-body-padding);
--panel-shadow-margin: var(--arrowpanel-shadow-margin);
--menuitem-border-radius: var(--arrowpanel-menuitem-border-radius);
--menuitem-padding: var(--arrowpanel-menuitem-padding);
--menuitem-margin: var(--arrowpanel-menuitem-margin);
}
menupopup {
@ -1188,7 +1184,6 @@ panelmultiview[mainViewId="PanelUI-fxa"] #PanelUI-remotetabs-syncnow {
display: none;
}
.toolbar-menupopup :is(menu, menuitem),
.subview-subheader,
panelview .toolbarbutton-1,
.subviewbutton,

View file

@ -32,6 +32,10 @@
&[sidebarcommand="viewGenaiChatSidebar"] {
min-width: 400px;
}
&[sidebarcommand="viewCPMSidebar"] {
min-width: 260px;
}
}
#sidebar-main,

View file

@ -155,7 +155,7 @@ def initialize(topsrcdir, args=()):
# Status messages from site.py break usages of `./mach environment`.
# We pass `quiet` only for it to work around this, so that all other
# commands can still write status messages.
if args and args[0] == "environment":
if args and (args[0] == "environment" or "--quiet" in args):
quiet = True
else:
quiet = False

View file

@ -231,8 +231,8 @@ uint32_t nsScriptSecurityManager::SecurityHashURI(nsIURI* aURI) {
bool nsScriptSecurityManager::IsHttpOrHttpsAndCrossOrigin(nsIURI* aUriA,
nsIURI* aUriB) {
if (!aUriA || (!net::SchemeIsHTTP(aUriA) && !net::SchemeIsHTTPS(aUriA)) ||
!aUriB || (!net::SchemeIsHTTP(aUriB) && !net::SchemeIsHTTPS(aUriB))) {
if (!aUriA || !net::SchemeIsHttpOrHttps(aUriA) || !aUriB ||
!net::SchemeIsHttpOrHttps(aUriB)) {
return false;
}
if (!SecurityCompareURIs(aUriA, aUriB)) {

View file

@ -21,6 +21,7 @@ import {
getPauseReason,
getSourceTextContent,
getCurrentThread,
getViewport,
} from "../../selectors/index";
import { features } from "../../utils/prefs";
@ -172,6 +173,15 @@ const mapStateToProps = state => {
if (!location) {
return {};
}
// For CM6, also check if we have a valid viewport.
// This is a way to know if the actual source is displayed
// and we are no longer on the "loading..." message
if (features.codemirrorNext) {
const viewport = getViewport(state);
if (!viewport) {
return {};
}
}
const sourceTextContent = getSourceTextContent(state, location);
if (!isDocumentReady(location, sourceTextContent)) {
return {};

View file

@ -161,6 +161,13 @@
color: #e7ebee;
}
/* At the moment, preview-token doesn't get a distinct style on hover (will be fixed in Bug 1953964 ).
This rule only make sure the text remains readable when hovering a token on the paused line. */
:root[forced-colors-active] .paused-line :is(.preview-token, .debug-expression.preview-token) {
color: inherit;
background-color: inherit;
}
.theme-dark .popover .preview-popup {
border-color: var(--theme-body-color);
}

View file

@ -3,25 +3,29 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
:root {
--breakpoint-active-color: rgba(44, 187, 15, 0.2);
--breakpoint-active-color-hover: rgba(44, 187, 15, 0.5);
--breakpoint-active-color: light-dark(
rgba(44, 187, 15, 0.2),
rgba(45, 210, 158, 0.5))
;
--breakpoint-active-color-hover: light-dark(
rgba(44, 187, 15, 0.5),
rgba(0, 255, 175, 0.7)
);
/* use 30% opacity to allow showing text selection background */
--paused-line-background: hsl(from var(--paused-background-color) h s calc( l * 0.7 ) / 30%);
--paused-line-background: light-dark(
hsl(from var(--paused-background-color) h s calc( l * 0.7 ) / 30%),
/* dark theme requires some specific luminosity factor */
hsl(from var(--paused-background-color) h s calc( l * 2 ) / 30%)
);
--paused-line-color: inherits;
--paused-line-border: var(--paused-color);
}
:root[forced-colors-active] {
--paused-line-background: Mark;
--paused-line-border: MarkText;
}
.theme-dark:root {
--breakpoint-active-color: rgba(45, 210, 158, 0.5);
--breakpoint-active-color-hover: rgba(0, 255, 175, 0.7);
/* dark theme requires some specific luminosity factor */
--paused-line-background: hsl(from var(--paused-background-color) h s calc( l * 2 ) / 30%);
--paused-line-color: MarkText;
--paused-line-border: SelectedItem;
}
.CodeMirror .errors {
@ -56,6 +60,7 @@
/* For CM6 */
.cm-editor .cm-line.paused-line {
background-color: var(--paused-line-background);
color: var(--paused-line-color);
outline: var(--paused-line-border) solid 1px;
}

View file

@ -180,10 +180,12 @@ class Editor extends EventEmitter {
};
#abortController;
// The id for the current source in the editor (selected source). This
// is used to cache the scroll snapshot for tracking scroll positions and the
// symbols.
// The id for the current source in the editor (selected source). This is used to:
// * cache the scroll snapshot for tracking scroll positions and the symbols,
// * know when an actual source is displayed (and not only a loading/error message)
#currentDocumentId = null;
#currentDocument = null;
#CodeMirror6;
#compartments;
@ -1762,6 +1764,10 @@ class Editor extends EventEmitter {
}
const cm = editors.get(this);
if (this.config.cm6) {
// Report no viewport until we show an actual source (and not a loading/error message)
if (!this.#currentDocumentId) {
return null;
}
const { from, to } = cm.viewport;
const lineFrom = cm.state.doc.lineAt(from);
const lineTo = cm.state.doc.lineAt(to);
@ -2519,8 +2525,10 @@ class Editor extends EventEmitter {
/**
* Replaces whatever is in the text area with the contents of
* the 'value' argument.
*
* @param {String} value: The text to replace the editor content
* @param {String} documentId: A unique id represeting the specific document which is source of the text.
* @param {String} documentId: Optional unique id represeting the specific document which is source of the text.
* Will be null for loading and error messages.
*/
async setText(value, documentId) {
const cm = editors.get(this);
@ -2528,6 +2536,10 @@ class Editor extends EventEmitter {
if (documentId) {
this.#currentDocumentId = documentId;
} else {
// Reset this ID when showing loading and error messages,
// so that we keep track when an actual source is displayed
this.#currentDocumentId = null;
}
if (isWasm) {

View file

@ -157,8 +157,15 @@ function createTargetsForWatcher(watcherDataObject, isProcessActorStartup) {
}
const topWindows = [];
for (const window of Services.ww.getWindowEnumerator()) {
topWindows.push(window);
// Do not use a for loop on `windowEnumerator` as underlying call to `getNext` may throw on some windows
const windowEnumerator = Services.ww.getWindowEnumerator();
while (windowEnumerator.hasMoreElements()) {
try {
const window = windowEnumerator.getNext();
topWindows.push(window);
} catch (e) {
console.error("Failed to process a top level window", e);
}
}
// When debugging an extension, we have to ensure create the top level target first.

View file

@ -924,8 +924,7 @@ async function doEagerEvalDOMGetters(commands) {
[`typeof document.lastModified`, "string"],
[`typeof document.readyState`, "string"],
[`typeof document.designMode`, "string"],
[`typeof document.onbeforescriptexecute`, "object"],
[`typeof document.onafterscriptexecute`, "object"],
[`typeof document.onabort`, "object"],
// Element
[`typeof document.documentElement.scrollTop`, "number"],

View file

@ -2040,7 +2040,7 @@ nsresult BrowsingContext::LoadURI(nsDocShellLoadState* aLoadState,
const auto& sourceBC = aLoadState->SourceBrowsingContext();
if (net::SchemeIsJavascript(aLoadState->URI())) {
if (aLoadState->URI()->SchemeIs("javascript")) {
if (!XRE_IsParentProcess()) {
// Web content should only be able to load javascript: URIs into documents
// whose principals the caller principal subsumes, which by definition
@ -2135,7 +2135,7 @@ nsresult BrowsingContext::InternalLoad(nsDocShellLoadState* aLoadState) {
const auto& sourceBC = aLoadState->SourceBrowsingContext();
if (net::SchemeIsJavascript(aLoadState->URI())) {
if (aLoadState->URI()->SchemeIs("javascript")) {
if (!XRE_IsParentProcess()) {
// Web content should only be able to load javascript: URIs into documents
// whose principals the caller principal subsumes, which by definition

View file

@ -2398,18 +2398,18 @@ bool CanonicalBrowsingContext::SupportsLoadingInParent(
// DocumentChannel currently only supports connecting channels into the
// content process, so we can only support schemes that will always be loaded
// there for now. Restrict to just http(s) for simplicity.
if (!net::SchemeIsHTTP(aLoadState->URI()) &&
!net::SchemeIsHTTPS(aLoadState->URI())) {
if (!net::SchemeIsHttpOrHttps(aLoadState->URI())) {
return false;
}
if (WindowGlobalParent* global = GetCurrentWindowGlobal()) {
nsCOMPtr<nsIURI> currentURI = global->GetDocumentURI();
if (currentURI) {
nsCOMPtr<nsIURI> uri = aLoadState->URI();
bool newURIHasRef = false;
aLoadState->URI()->GetHasRef(&newURIHasRef);
uri->GetHasRef(&newURIHasRef);
bool equalsExceptRef = false;
aLoadState->URI()->EqualsExceptRef(currentURI, &equalsExceptRef);
uri->EqualsExceptRef(currentURI, &equalsExceptRef);
if (equalsExceptRef && newURIHasRef) {
// This navigation is same-doc WRT the current one, we should pass it
@ -2454,7 +2454,7 @@ bool CanonicalBrowsingContext::LoadInParent(nsDocShellLoadState* aLoadState,
return false;
}
MOZ_ASSERT(!net::SchemeIsJavascript(aLoadState->URI()));
MOZ_ASSERT(!aLoadState->URI()->SchemeIs("javascript"));
MOZ_ALWAYS_SUCCEEDS(
SetParentInitiatedNavigationEpoch(++gParentInitiatedNavigationEpoch));

View file

@ -667,7 +667,7 @@ nsDocShell::SetCancelContentJSEpoch(int32_t aEpoch) {
nsresult nsDocShell::CheckDisallowedJavascriptLoad(
nsDocShellLoadState* aLoadState) {
if (!net::SchemeIsJavascript(aLoadState->URI())) {
if (!aLoadState->URI()->SchemeIs("javascript")) {
return NS_OK;
}
@ -1616,8 +1616,8 @@ nsDocShell::ForceEncodingDetection() {
mForcedAutodetection = true;
nsIURI* url = doc->GetOriginalURI();
bool isFileURL = url && SchemeIsFile(url);
nsIURI* uri = doc->GetOriginalURI();
bool isFileURL = uri && uri->SchemeIs("file");
int32_t charsetSource = doc->GetDocumentCharacterSetSource();
auto encoding = doc->GetDocumentCharacterSet();
@ -3710,7 +3710,7 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
if (aURI) {
// displaying "file://" is aesthetically unpleasing and could even be
// confusing to the user
if (SchemeIsFile(aURI)) {
if (aURI->SchemeIs("file")) {
aURI->GetPathQueryRef(spec);
} else {
aURI->GetSpec(spec);
@ -3740,7 +3740,7 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
NS_ENSURE_FALSE(messageStr.IsEmpty(), NS_ERROR_FAILURE);
if ((NS_ERROR_NET_INTERRUPT == aError || NS_ERROR_NET_RESET == aError) &&
SchemeIsHTTPS(aURI)) {
aURI->SchemeIs("https")) {
// Maybe TLS intolerant. Treat this as an SSL error.
error = "nssFailure2";
}
@ -5780,7 +5780,7 @@ already_AddRefed<nsIURI> nsDocShell::MaybeFixBadCertDomainErrorURI(
}
// Return if scheme is not HTTPS.
if (!SchemeIsHTTPS(aUrl)) {
if (!aUrl->SchemeIs("https")) {
return nullptr;
}
@ -5949,10 +5949,8 @@ already_AddRefed<nsIURI> nsDocShell::AttemptURIFixup(
// Someone needs to clean up keywords in general so we can
// determine on a per url basis if we want keywords
// enabled...this is just a bandaid...
nsAutoCString scheme;
Unused << url->GetScheme(scheme);
if (Preferences::GetBool("keyword.enabled", false) &&
StringBeginsWith(scheme, "http"_ns)) {
net::SchemeIsHttpOrHttps(url)) {
bool attemptFixup = false;
nsAutoCString host;
Unused << url->GetHost(host);
@ -6050,7 +6048,7 @@ already_AddRefed<nsIURI> nsDocShell::AttemptURIFixup(
} else if (aStatus == NS_ERROR_CONNECTION_REFUSED &&
Preferences::GetBool("browser.fixup.fallback-to-https", false)) {
// Try HTTPS, since http didn't work
if (SchemeIsHTTP(url)) {
if (url->SchemeIs("http")) {
int32_t port = 0;
url->GetPort(&port);
@ -9309,7 +9307,7 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState,
MOZ_DIAGNOSTIC_ASSERT(aLoadState->LoadType() == LOAD_NORMAL);
// Disallow external chrome: loads targetted at content windows
if (SchemeIsChrome(aLoadState->URI())) {
if (aLoadState->URI()->SchemeIs("chrome")) {
NS_WARNING("blocked external chrome: url -- use '--chrome' option");
return NS_ERROR_FAILURE;
}
@ -9353,7 +9351,7 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState,
// XXXbz mTiming should know what channel it's for, so we don't
// need this hackery.
const bool isJavaScript = SchemeIsJavascript(aLoadState->URI());
const bool isJavaScript = aLoadState->URI()->SchemeIs("javascript");
const bool isExternalProtocol =
nsContentUtils::IsExternalProtocol(aLoadState->URI());
const bool isDownload = !aLoadState->FileName().IsVoid();
@ -9733,7 +9731,7 @@ nsIPrincipal* nsDocShell::GetInheritedPrincipal(
MOZ_ALWAYS_SUCCEEDS(vsc->SetBaseURI(aBaseURI));
}
}
} else if (SchemeIsViewSource(aURI)) {
} else if (aURI->SchemeIs("view-source")) {
// Instantiate view source handler protocol, if it doesn't exist already.
nsCOMPtr<nsIIOService> io(do_GetIOService());
MOZ_ASSERT(io);
@ -10239,7 +10237,7 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
while (nestedURI) {
// view-source should always be an nsINestedURI, loop and check the
// scheme on this and all inner URIs that are also nested URIs.
if (SchemeIsViewSource(tempURI)) {
if (tempURI->SchemeIs("view-source")) {
return NS_ERROR_UNKNOWN_PROTOCOL;
}
nestedURI->GetInnerURI(getter_AddRefs(tempURI));
@ -10256,20 +10254,21 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
// configured as unique opaque origin.
bool inheritPrincipal = false;
nsCOMPtr<nsIURI> uri = aLoadState->URI();
if (aLoadState->PrincipalToInherit()) {
bool isSrcdoc =
aLoadState->HasInternalLoadFlags(INTERNAL_LOAD_FLAGS_IS_SRCDOC);
bool inheritAttrs = nsContentUtils::ChannelShouldInheritPrincipal(
aLoadState->PrincipalToInherit(), aLoadState->URI(),
aLoadState->PrincipalToInherit(), uri,
true, // aInheritForAboutBlank
isSrcdoc);
inheritPrincipal = inheritAttrs && !SchemeIsData(aLoadState->URI());
inheritPrincipal = inheritAttrs && !uri->SchemeIs("data");
}
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1736570
const bool isAboutBlankLoadOntoInitialAboutBlank =
IsAboutBlankLoadOntoInitialAboutBlank(aLoadState->URI(), inheritPrincipal,
IsAboutBlankLoadOntoInitialAboutBlank(uri, inheritPrincipal,
aLoadState->PrincipalToInherit());
// FIXME We still have a ton of codepaths that don't pass through
@ -10282,7 +10281,7 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
// Materialize LoadingSessionHistoryInfo here, because DocumentChannel
// loads have it, and later history behavior depends on it existing.
UniquePtr<SessionHistoryInfo> entry = MakeUnique<SessionHistoryInfo>(
aLoadState->URI(), aLoadState->TriggeringPrincipal(),
uri, aLoadState->TriggeringPrincipal(),
aLoadState->PrincipalToInherit(),
aLoadState->PartitionedPrincipalToInherit(), aLoadState->Csp(),
mContentTypeHint);
@ -10394,8 +10393,7 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
aLoadState->GetLoadIdentifier());
RefPtr<LoadInfo> loadInfo =
(contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT)
? new LoadInfo(loadingWindow, aLoadState->URI(),
aLoadState->TriggeringPrincipal(),
? new LoadInfo(loadingWindow, uri, aLoadState->TriggeringPrincipal(),
topLevelLoadingContext, securityFlags, sandboxFlags)
: new LoadInfo(loadingPrincipal, aLoadState->TriggeringPrincipal(),
loadingNode, securityFlags, contentPolicyType,
@ -10502,7 +10500,7 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
mBrowsingContext, uriModified, Some(isEmbeddingBlockedError));
nsCOMPtr<nsIChannel> channel;
if (DocumentChannel::CanUseDocumentChannel(aLoadState->URI()) &&
if (DocumentChannel::CanUseDocumentChannel(uri) &&
!isAboutBlankLoadOntoInitialAboutBlank) {
channel = DocumentChannel::CreateForDocument(
aLoadState, loadInfo, loadFlags, this, cacheKey, uriModified,
@ -12065,7 +12063,7 @@ nsresult nsDocShell::LoadHistoryEntry(nsDocShellLoadState* aLoadState,
aLoadState->SetLoadType(aLoadType);
nsresult rv;
if (SchemeIsJavascript(aLoadState->URI())) {
if (aLoadState->URI()->SchemeIs("javascript")) {
// We're loading a URL that will execute script from inside asyncOpen.
// Replace the current document with about:blank now to prevent
// anything from the current document from leaking into any JavaScript
@ -12908,7 +12906,7 @@ nsresult nsDocShell::OnLinkClick(
bool nsDocShell::ShouldOpenInBlankTarget(const nsAString& aOriginalTarget,
nsIURI* aLinkURI, nsIContent* aContent,
bool aIsUserTriggered) {
if (net::SchemeIsJavascript(aLinkURI)) {
if (aLinkURI->SchemeIs("javascript")) {
return false;
}

View file

@ -278,7 +278,7 @@ static void ForEachPing(nsIContent* aContent, ForEachPingCallback aCallback,
continue;
}
// Explicitly not allow loading data: URIs
if (!net::SchemeIsData(uri)) {
if (!uri->SchemeIs("data")) {
aCallback(aClosure, aContent, uri, ios);
}
}

View file

@ -5372,43 +5372,20 @@ void Element::SetHTML(const nsAString& aInnerHTML,
// We MUST NOT cause any requests during parsing, so we'll
// create an inert Document and parse into a new DocumentFragment.
RefPtr<Document> inertDoc;
nsAtom* contextLocalName = parseContext->NodeInfo()->NameAtom();
int32_t contextNameSpaceID = parseContext->GetNameSpaceID();
ElementCreationOptionsOrString options;
RefPtr<DocumentFragment> fragment;
if (doc->IsHTMLDocument()) {
inertDoc = nsContentUtils::CreateInertHTMLDocument(doc);
if (!inertDoc) {
aError = NS_ERROR_FAILURE;
return;
}
fragment = new (inertDoc->NodeInfoManager())
DocumentFragment(inertDoc->NodeInfoManager());
aError = nsContentUtils::ParseFragmentHTML(aInnerHTML, fragment,
contextLocalName,
contextNameSpaceID, false, true);
} else {
MOZ_ASSERT(doc->IsXMLDocument());
inertDoc = nsContentUtils::CreateInertXMLDocument(doc);
if (!inertDoc) {
aError = NS_ERROR_FAILURE;
return;
}
fragment = new (inertDoc->NodeInfoManager())
DocumentFragment(inertDoc->NodeInfoManager());
// TODO(freddyb) `nsContentUtils::CreateContextualFragment` is actually
// collecting a ton of stacks to get in an (X)HTMLish state.
// I'm afraid we might need that too. Ugh.
AutoTArray<nsString, 0> emptyTagStack;
aError =
nsContentUtils::ParseFragmentXML(aInnerHTML, inertDoc, emptyTagStack,
true, -1, getter_AddRefs(fragment));
RefPtr<Document> inertDoc = nsContentUtils::CreateInertHTMLDocument(doc);
if (!inertDoc) {
aError = NS_ERROR_FAILURE;
return;
}
RefPtr<DocumentFragment> fragment = new (inertDoc->NodeInfoManager())
DocumentFragment(inertDoc->NodeInfoManager());
nsAtom* contextLocalName = parseContext->NodeInfo()->NameAtom();
int32_t contextNameSpaceID = parseContext->GetNameSpaceID();
aError = nsContentUtils::ParseFragmentHTML(
aInnerHTML, fragment, contextLocalName, contextNameSpaceID, false, true);
if (aError.Failed()) {
return;
}

View file

@ -826,7 +826,7 @@ EventSourceImpl::AsyncOnChannelRedirect(
rv = NS_GetFinalChannelURI(aNewChannel, getter_AddRefs(newURI));
NS_ENSURE_SUCCESS(rv, rv);
bool isValidScheme = newURI->SchemeIs("http") || newURI->SchemeIs("https");
bool isValidScheme = net::SchemeIsHttpOrHttps(newURI);
rv =
mIsMainThread ? GetEventSource()->CheckCurrentGlobalCorrectness() : NS_OK;
@ -988,7 +988,7 @@ nsresult EventSourceImpl::InitChannelAndRequestEventSource(
return NS_ERROR_ABORT;
}
bool isValidScheme = mSrc->SchemeIs("http") || mSrc->SchemeIs("https");
bool isValidScheme = net::SchemeIsHttpOrHttps(mSrc);
MOZ_ASSERT_IF(mIsMainThread, aEventTargetAccessAllowed);

View file

@ -13,6 +13,7 @@
#include "mozilla/dom/WindowBinding.h"
#include "nsComponentManagerUtils.h"
#include "nsPIDOMWindow.h"
#include "mozilla/dom/WebTaskScheduler.h"
namespace mozilla::dom {
@ -54,7 +55,20 @@ void IdleRequest::IdleRun(nsPIDOMWindowInner* aWindow,
new IdleDeadline(aWindow, aDidTimeout, aDeadline);
RefPtr<IdleRequestCallback> callback(std::move(mCallback));
MOZ_ASSERT(!mCallback);
RefPtr<nsGlobalWindowInner> innerWindow = nsGlobalWindowInner::Cast(aWindow);
// https://wicg.github.io/scheduling-apis/#sec-patches-invoke-idle-callbacks
// Let state be a new scheduling state.
RefPtr<WebTaskSchedulingState> newState = new WebTaskSchedulingState();
// Set states priority source to the result of creating a fixed priority
// unabortable task signal given "background" and realm.
newState->SetPrioritySource(
new TaskSignal(aWindow->AsGlobal(), TaskPriority::Background));
// Set event loops current scheduling state to state.
innerWindow->SetWebTaskSchedulingState(newState);
callback->Call(*deadline, "requestIdleCallback handler");
// Set event loops current scheduling state to null.
innerWindow->SetWebTaskSchedulingState(nullptr);
}
} // namespace mozilla::dom

View file

@ -456,7 +456,7 @@ void Location::SetProtocol(const nsACString& aProtocol,
return;
}
if (!uri->SchemeIs("http") && !uri->SchemeIs("https")) {
if (!net::SchemeIsHttpOrHttps(uri)) {
// No-op, per spec.
return;
}

View file

@ -162,7 +162,7 @@ void LocationBase::SetURI(nsIURI* aURI, nsIPrincipal& aSubjectPrincipal,
rv = bc->LoadURI(loadState);
if (NS_WARN_IF(NS_FAILED(rv))) {
if (rv == NS_ERROR_DOM_BAD_CROSS_ORIGIN_URI &&
net::SchemeIsJavascript(loadState->URI())) {
loadState->URI()->SchemeIs("javascript")) {
// Per spec[1], attempting to load a javascript: URI into a cross-origin
// BrowsingContext is a no-op, and should not raise an exception.
// Technically, Location setters run with exceptions enabled should only

View file

@ -1236,7 +1236,7 @@ bool Navigator::SendBeaconInternal(const nsAString& aUrl,
}
// Spec disallows any schemes save for HTTP/HTTPs
if (!uri->SchemeIs("http") && !uri->SchemeIs("https")) {
if (!net::SchemeIsHttpOrHttps(uri)) {
aRv.ThrowTypeError<MSG_INVALID_URL_SCHEME>("Beacon",
uri->GetSpecOrDefault());
return false;

View file

@ -455,7 +455,7 @@ ThirdPartyUtil::GetBaseDomain(nsIURI* aHostURI, nsACString& aBaseDomain) {
// The aHostURI can be a view-source URI, in which case we need to get the
// base domain from the inner most URI.
if (net::SchemeIsViewSource(aHostURI)) {
if (aHostURI->SchemeIs("view-source")) {
rv = NS_GetInnermostURIHost(aHostURI, aBaseDomain);
} else {
rv = aHostURI->GetAsciiHost(aBaseDomain);

View file

@ -24,6 +24,7 @@
#include "mozilla/net/WebSocketEventService.h"
#include "mozilla/MediaManager.h"
#include "mozilla/dom/WorkerScope.h"
#include "mozilla/dom/WebTaskScheduler.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -675,6 +676,17 @@ void TimeoutManager::RunTimeout(const TimeStamp& aNow,
return;
}
if (!GetInnerWindow()) {
// Workers don't use TaskController at the moment, so all the
// runnables have the same priorities. So we special case it
// here to allow "higher" prority tasks to run first before
// timers.
if (mGlobalObject.HasScheduledNormalOrHighPriorityWebTasks()) {
MOZ_ALWAYS_SUCCEEDS(MaybeSchedule(aNow));
return;
}
}
Timeouts& timeouts(aProcessIdle ? mIdleTimeouts : mTimeouts);
// Limit the overall time spent in RunTimeout() to reduce jank.
@ -976,8 +988,12 @@ void TimeoutManager::RunTimeout(const TimeStamp& aNow,
}
// Check to see if we have run out of time to execute timeout handlers.
// If we've exceeded our time budget then terminate the loop immediately.
//
// Or if there are high priority tasks dispatched by the Scheduler API,
// they should run first before timers.
TimeDuration elapsed = now - start;
if (elapsed >= totalTimeLimit) {
if (elapsed >= totalTimeLimit ||
mGlobalObject.HasScheduledNormalOrHighPriorityWebTasks()) {
// We ran out of time. Make sure to schedule the executor to
// run immediately for the next timer, if it exists. Its possible,
// however, that the last timeout handler suspended the window. If

View file

@ -106,6 +106,7 @@
#include "mozilla/Preferences.h"
#include "mozilla/PresShell.h"
#include "mozilla/ProfilerRunnable.h"
#include "mozilla/FlowMarkers.h"
#include "mozilla/RangeBoundary.h"
#include "mozilla/RefPtr.h"
#include "mozilla/Result.h"
@ -5136,12 +5137,13 @@ static already_AddRefed<Event> GetEventWithTarget(
nsresult nsContentUtils::DispatchTrustedEvent(
Document* aDoc, EventTarget* aTarget, const nsAString& aEventName,
CanBubble aCanBubble, Cancelable aCancelable, Composed aComposed,
bool* aDefaultAction) {
bool* aDefaultAction, SystemGroupOnly aSystemGroupOnly) {
MOZ_ASSERT(!aEventName.EqualsLiteral("input") &&
!aEventName.EqualsLiteral("beforeinput"),
"Use DispatchInputEvent() instead");
return DispatchEvent(aDoc, aTarget, aEventName, aCanBubble, aCancelable,
aComposed, Trusted::eYes, aDefaultAction);
aComposed, Trusted::eYes, aDefaultAction,
ChromeOnlyDispatch::eNo, aSystemGroupOnly);
}
// static
@ -5153,13 +5155,11 @@ nsresult nsContentUtils::DispatchUntrustedEvent(
}
// static
nsresult nsContentUtils::DispatchEvent(Document* aDoc, EventTarget* aTarget,
const nsAString& aEventName,
CanBubble aCanBubble,
Cancelable aCancelable,
Composed aComposed, Trusted aTrusted,
bool* aDefaultAction,
ChromeOnlyDispatch aOnlyChromeDispatch) {
nsresult nsContentUtils::DispatchEvent(
Document* aDoc, EventTarget* aTarget, const nsAString& aEventName,
CanBubble aCanBubble, Cancelable aCancelable, Composed aComposed,
Trusted aTrusted, bool* aDefaultAction,
ChromeOnlyDispatch aOnlyChromeDispatch, SystemGroupOnly aSystemGroupOnly) {
if (!aDoc || !aTarget) {
return NS_ERROR_INVALID_ARG;
}
@ -5173,6 +5173,8 @@ nsresult nsContentUtils::DispatchEvent(Document* aDoc, EventTarget* aTarget,
}
event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch =
aOnlyChromeDispatch == ChromeOnlyDispatch::eYes;
event->WidgetEventPtr()->mFlags.mOnlySystemGroupDispatch =
aSystemGroupOnly == SystemGroupOnly::eYes;
bool doDefault = aTarget->DispatchEvent(*event, CallerType::System, err);
if (aDefaultAction) {
@ -6631,6 +6633,8 @@ void nsContentUtils::AddScriptRunner(already_AddRefed<nsIRunnable> aRunnable) {
}
if (sScriptBlockerCount) {
PROFILER_MARKER("nsContentUtils::AddScriptRunner", OTHER, {},
FlowMarker, Flow::FromPointer(runnable.get()));
sBlockedScriptRunners->AppendElement(runnable.forget());
return;
}
@ -7113,8 +7117,8 @@ nsresult nsContentUtils::GetWebExposedOriginSerialization(nsIURI* aURI,
if (
// Schemes in spec. https://url.spec.whatwg.org/#origin
!uri->SchemeIs("http") && !uri->SchemeIs("https") &&
!uri->SchemeIs("file") && !uri->SchemeIs("resource") &&
!net::SchemeIsHttpOrHttps(uri) && !uri->SchemeIs("file") &&
!uri->SchemeIs("resource") &&
// Our own schemes.
!uri->SchemeIs("moz-extension")) {
aOrigin.AssignLiteral("null");

View file

@ -266,6 +266,7 @@ class nsContentUtils {
using Trusted = mozilla::Trusted;
using JSONBehavior = mozilla::dom::JSONBehavior;
using RFPTarget = mozilla::RFPTarget;
using SystemGroupOnly = mozilla::SystemGroupOnly;
public:
static nsresult Init();
@ -1556,24 +1557,22 @@ class nsContentUtils {
*/
// TODO: annotate with `MOZ_CAN_RUN_SCRIPT`
// (https://bugzilla.mozilla.org/show_bug.cgi?id=1625902).
static nsresult DispatchTrustedEvent(Document* aDoc,
mozilla::dom::EventTarget* aTarget,
const nsAString& aEventName, CanBubble,
Cancelable,
Composed aComposed = Composed::eDefault,
bool* aDefaultAction = nullptr);
static nsresult DispatchTrustedEvent(
Document* aDoc, mozilla::dom::EventTarget* aTarget,
const nsAString& aEventName, CanBubble, Cancelable,
Composed aComposed = Composed::eDefault, bool* aDefaultAction = nullptr,
SystemGroupOnly aSystemGroupOnly = SystemGroupOnly::eNo);
// TODO: annotate with `MOZ_CAN_RUN_SCRIPT`
// (https://bugzilla.mozilla.org/show_bug.cgi?id=1625902).
static nsresult DispatchTrustedEvent(Document* aDoc,
mozilla::dom::EventTarget* aTarget,
const nsAString& aEventName,
CanBubble aCanBubble,
Cancelable aCancelable,
bool* aDefaultAction) {
static nsresult DispatchTrustedEvent(
Document* aDoc, mozilla::dom::EventTarget* aTarget,
const nsAString& aEventName, CanBubble aCanBubble, Cancelable aCancelable,
bool* aDefaultAction,
SystemGroupOnly aSystemGroupOnly = SystemGroupOnly::eNo) {
return DispatchTrustedEvent(aDoc, aTarget, aEventName, aCanBubble,
aCancelable, Composed::eDefault,
aDefaultAction);
aCancelable, Composed::eDefault, aDefaultAction,
aSystemGroupOnly);
}
/**
@ -3577,7 +3576,8 @@ class nsContentUtils {
Document* aDoc, mozilla::dom::EventTarget* aTarget,
const nsAString& aEventName, CanBubble, Cancelable, Composed, Trusted,
bool* aDefaultAction = nullptr,
ChromeOnlyDispatch = ChromeOnlyDispatch::eNo);
ChromeOnlyDispatch = ChromeOnlyDispatch::eNo,
SystemGroupOnly = SystemGroupOnly::eNo);
// TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
MOZ_CAN_RUN_SCRIPT_BOUNDARY static nsresult DispatchEvent(

View file

@ -293,13 +293,14 @@ CompositorBridgeChild* nsDOMWindowUtils::GetCompositorBridge() {
nsresult nsDOMWindowUtils::GetWidgetOpaqueRegion(
nsTArray<RefPtr<DOMRect>>& aRects) {
const nsPresContext* pc = GetPresContext();
nsIWidget* widget = GetWidget();
if (!widget) {
if (!widget || !pc) {
return NS_ERROR_FAILURE;
}
auto AddRect = [&](const LayoutDeviceIntRect& aRect) {
RefPtr rect = new DOMRect(mWindow);
CSSRect cssRect = aRect / widget->GetDefaultScale();
CSSRect cssRect = aRect / pc->CSSToDevPixelScale();
rect->SetRect(cssRect.x, cssRect.y, cssRect.width, cssRect.height);
aRects.AppendElement(std::move(rect));
};

View file

@ -169,8 +169,8 @@ NS_IMPL_CYCLE_COLLECTION_WEAK(nsFocusManager, mActiveWindow,
mActiveBrowsingContextInChrome, mFocusedWindow,
mFocusedBrowsingContextInContent,
mFocusedBrowsingContextInChrome, mFocusedElement,
mFirstBlurEvent, mFirstFocusEvent,
mWindowBeingLowered, mDelayedBlurFocusEvents)
mFirstBlurEvent, mWindowBeingLowered,
mDelayedBlurFocusEvents)
StaticRefPtr<nsFocusManager> nsFocusManager::sInstance;
bool nsFocusManager::sTestMode = false;
@ -249,7 +249,6 @@ nsFocusManager::Observe(nsISupports* aSubject, const char* aTopic,
mFocusedBrowsingContextInChrome = nullptr;
mFocusedElement = nullptr;
mFirstBlurEvent = nullptr;
mFirstFocusEvent = nullptr;
mWindowBeingLowered = nullptr;
mDelayedBlurFocusEvents.Clear();
}
@ -2594,8 +2593,7 @@ void nsFocusManager::Focus(
return;
}
if (aElement &&
(aElement == mFirstFocusEvent || aElement == mFirstBlurEvent)) {
if (aElement && aElement == mFirstBlurEvent) {
return;
}
@ -2657,12 +2655,6 @@ void nsFocusManager::Focus(
return;
}
Maybe<AutoRestore<RefPtr<Element>>> ar;
if (!mFirstFocusEvent) {
ar.emplace(mFirstFocusEvent);
mFirstFocusEvent = aElement;
}
LOGCONTENT("Element %s has been focused", aElement);
if (MOZ_LOG_TEST(gFocusLog, LogLevel::Debug)) {
@ -5559,10 +5551,6 @@ void nsFocusManager::MarkUncollectableForCCGeneration(uint32_t aGeneration) {
sInstance->mFirstBlurEvent->OwnerDoc()->MarkUncollectableForCCGeneration(
aGeneration);
}
if (sInstance->mFirstFocusEvent) {
sInstance->mFirstFocusEvent->OwnerDoc()->MarkUncollectableForCCGeneration(
aGeneration);
}
}
bool nsFocusManager::CanSkipFocus(nsIContent* aContent) {

View file

@ -993,11 +993,10 @@ class nsFocusManager final : public nsIFocusManager,
// focused.
RefPtr<mozilla::dom::Element> mFocusedElement;
// these fields store a content node temporarily while it is being focused
// or blurred to ensure that a recursive call doesn't refire the same event.
// This field stores a content node temporarily while it is being blurred
// to ensure that a recursive call doesn't refire the same event.
// They will always be cleared afterwards.
RefPtr<mozilla::dom::Element> mFirstBlurEvent;
RefPtr<mozilla::dom::Element> mFirstFocusEvent;
// keep track of a window while it is being lowered
nsCOMPtr<nsPIDOMWindowOuter> mWindowBeingLowered;

View file

@ -1400,6 +1400,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindowInner)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebTaskScheduler)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebTaskSchedulingState)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTrustedTypePolicyFactory)
#ifdef MOZ_WEBSPEECH
@ -1511,6 +1513,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindowInner)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWebTaskScheduler)
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWebTaskSchedulingState)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTrustedTypePolicyFactory)
#ifdef MOZ_WEBSPEECH
@ -1827,6 +1831,7 @@ void nsGlobalWindowInner::InitDocumentDependentState(JSContext* aCx) {
if (mWebTaskScheduler) {
mWebTaskScheduler->Disconnect();
mWebTaskScheduler = nullptr;
mWebTaskSchedulingState = nullptr;
}
// This must be called after nullifying the internal objects because here we
@ -2902,6 +2907,10 @@ bool nsPIDOMWindowInner::IsCurrentInnerWindow() const {
return outer && outer->GetCurrentInnerWindow() == this;
}
bool nsGlobalWindowInner::HasScheduledNormalOrHighPriorityWebTasks() const {
return gNumNormalOrHighPriorityQueuesHaveTaskScheduledMainThread > 0;
}
bool nsPIDOMWindowInner::IsFullyActive() const {
WindowContext* wc = GetWindowContext();
if (!wc || wc->IsDiscarded() || !wc->IsCurrent()) {
@ -4102,6 +4111,11 @@ WebTaskScheduler* nsGlobalWindowInner::Scheduler() {
return mWebTaskScheduler;
}
inline void nsGlobalWindowInner::SetWebTaskSchedulingState(
WebTaskSchedulingState* aState) {
mWebTaskSchedulingState = aState;
}
bool nsGlobalWindowInner::Find(const nsAString& aString, bool aCaseSensitive,
bool aBackwards, bool aWrapAround,
bool aWholeWord, bool aSearchInFrames,

View file

@ -130,6 +130,7 @@ class Selection;
struct SizeToContentConstraints;
class WebTaskScheduler;
class WebTaskSchedulerMainThread;
class WebTaskSchedulingState;
class SpeechSynthesis;
class Timeout;
class TrustedTypePolicyFactory;
@ -337,6 +338,7 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
virtual bool HasActiveIndexedDBDatabases() override;
virtual bool HasActivePeerConnections() override;
virtual bool HasOpenWebSockets() const override;
virtual bool HasScheduledNormalOrHighPriorityWebTasks() const override;
void SyncStateFromParentWindow();
// Called on the current inner window of a browsing context when its
@ -963,6 +965,12 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
bool OriginAgentCluster() const;
mozilla::dom::WebTaskScheduler* Scheduler();
void SetWebTaskSchedulingState(
mozilla::dom::WebTaskSchedulingState* aState) override;
mozilla::dom::WebTaskSchedulingState* GetWebTaskSchedulingState()
const override {
return mWebTaskSchedulingState;
}
protected:
// Web IDL helpers
@ -1279,6 +1287,7 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
RefPtr<mozilla::dom::ContentMediaController> mContentMediaController;
RefPtr<mozilla::dom::WebTaskSchedulerMainThread> mWebTaskScheduler;
RefPtr<mozilla::dom::WebTaskSchedulingState> mWebTaskSchedulingState;
RefPtr<mozilla::dom::TrustedTypePolicyFactory> mTrustedTypePolicyFactory;

View file

@ -53,6 +53,7 @@ class ServiceWorkerContainer;
class ServiceWorkerRegistration;
class ServiceWorkerRegistrationDescriptor;
class StorageManager;
class WebTaskSchedulingState;
enum class CallerType : uint32_t;
} // namespace dom
namespace ipc {
@ -194,6 +195,13 @@ class nsIGlobalObject : public nsISupports {
return nullptr;
}
virtual void SetWebTaskSchedulingState(
mozilla::dom::WebTaskSchedulingState* aState) {}
virtual mozilla::dom::WebTaskSchedulingState* GetWebTaskSchedulingState()
const {
return nullptr;
}
// For globals with a concept of a Base URI (windows, workers), the base URI,
// nullptr otherwise.
virtual nsIURI* GetBaseURI() const;
@ -339,6 +347,10 @@ class nsIGlobalObject : public nsISupports {
virtual bool IsXPCSandbox() { return false; }
virtual bool HasScheduledNormalOrHighPriorityWebTasks() const {
return false;
}
/**
* Report a localized error message to the error console. Currently this
* amounts to a wrapper around nsContentUtils::ReportToConsole for window

View file

@ -1402,7 +1402,7 @@ nsresult nsObjectLoadingContent::OpenChannel() {
true, // aInheritForAboutBlank
false); // aForceInherit
bool inheritPrincipal = inheritAttrs && !SchemeIsData(mURI);
bool inheritPrincipal = inheritAttrs && !mURI->SchemeIs("data");
nsSecurityFlags securityFlags =
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL;

View file

@ -12,15 +12,24 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=587931
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=587931">Mozilla Bug 587931</a>
<pre id="test">
<script type="application/javascript">
var { AppConstants } = SpecialPowers.ChromeUtils.importESModule(
"resource://gre/modules/AppConstants.sys.mjs"
);
/** Test for Bug 587931 **/
SimpleTest.waitForExplicitFinish();
var afterCount = 0;
var lastBeforeExecute = null;
var afterCountForSystemGroup = 0;
// For system group
var afterCountForSystemGroup = 0;
var lastBeforeExecuteForSystemGroup = null;
var expectedCurrentScriptInAfterScriptExecute = null;
function verifyScript(n) {
var curr = document.currentScript;
is(curr, document.getElementById(n), "correct script (" + n + ")");
is(lastBeforeExecute, curr, "correct beforescript (" + n + ")");
is(lastBeforeExecute, AppConstants.NIGHTLY_BUILD ? null : curr, "correct beforescript (" + n + ")");
document.addEventListener("afterscriptexecute", function(event) {
afterCount++;
lastBeforeExecute = null;
@ -29,13 +38,26 @@ function verifyScript(n) {
"document.currentScript in afterscriptexecute(" + n + ")");
document.removeEventListener("afterscriptexecute", arguments.callee);
});
// Test system group
SpecialPowers.wrap(document).addEventListener("afterscriptexecute", function(event) {
afterCountForSystemGroup++;
lastBeforeExecuteForSystemGroup = null;
is(event.target, curr, "correct afterscript (" + n + ") for system group");
is(document.currentScript, expectedCurrentScriptInAfterScriptExecute,
"document.currentScript in afterscriptexecute(" + n + ") for system group");
}, { mozSystemGroup: true, once: true });
}
document.onbeforescriptexecute = function(event) {
lastBeforeExecute = event.target;
};
// Test system group
SpecialPowers.wrap(document).addEventListener("beforescriptexecute", function(event) {
lastBeforeExecuteForSystemGroup = event.target;
}, { mozSystemGroup: true });
window.addEventListener("load", function() {
is(afterCount, 4, "correct number of afterscriptexecute");
is(afterCount, AppConstants.NIGHTLY_BUILD ? 0 : 4, "correct number of afterscriptexecute");
is(afterCountForSystemGroup, 4, "correct number of afterscriptexecute for system group");
SimpleTest.finish();
});
</script>
@ -64,17 +86,17 @@ document.body.appendChild(s);
<!-- Test cancel using beforescriptexecute -->
<script onbeforescriptexecute="return false;"
onafterescriptexecute="window.firedAfterScriptExecuteForCancel = true;">
ok(false, "should have been canceled");
ok(AppConstants.NIGHTLY_BUILD, "should have been canceled");
</script>
<script>
isnot(window.firedAfterScriptExecuteForCancel, true, "onafterscriptexecute executed");
</script>
<!-- Test cancel using beforescriptexecute for external -->
<script onbeforescriptexecute="return false;"
<script onbeforescriptexecute="window.extFiredBeforeScriptExecuteForCancel = true; return false;"
onafterescriptexecute="window.extFiredAfterScriptExecuteForCancel = true;"
onload="window.extFiredLoadForCancel = true;"
src="data:text/plain,ok(false, 'should have been canceled');">
src="data:text/plain,ok(!window.extFiredBeforeScriptExecuteForCancel, 'should have been canceled');">
</script>
<script>
isnot(window.extFiredAfterScriptExecuteForCancel, true, "onafterscriptexecute executed");
@ -86,17 +108,17 @@ is(extFiredLoadForCancel, true, "onload executed");
onafterscriptexecute="window.afterDidExecute = true;"
onload="window.loadDidExecute = true"
onerror="window.errorDidExecute = true"
src="data:text/plain,
is(window.beforeDidExecute, true, 'onbeforescriptexecute executed');
isnot(window.afterDidExecute, true, 'onafterscriptexecute executed');
isnot(window.loadDidExecute, true, 'onload executed');
isnot(window.errorDidExecute, true, 'onerror executed');
">
src="data:text/plain,window.didExecute=true">
is(window.beforeDidExecute, AppConstants.NIGHTLY_BUILD ? undefined : true, 'onbeforescriptexecute executed');
is(window.afterDidExecute, undefined, 'onafterscriptexecute executed');
is(window.didExecute, true, 'script executed');
is(window.loadDidExecute, undefined, 'onload executed');
is(window.errorDidExecute, undefined, 'onerror executed');
</script>
<script>
is(afterDidExecute, true, "onafterscriptexecute executed");
is(loadDidExecute, true, "onload executed");
isnot(window.errorDidExecute, true, "onerror executed");
is(window.afterDidExecute, AppConstants.NIGHTLY_BUILD ? undefined : true, "onafterscriptexecute executed");
is(window.loadDidExecute, true, "onload executed");
is(window.errorDidExecute, undefined, "onerror executed");
</script>
</body>
</html>

View file

@ -781,6 +781,29 @@ nsresult IMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
: GetNewIMEState(*aPresContext, aElement);
bool setIMEState = true;
const auto CanSkipSettingContext = [&](const InputContext& aOldContext) {
const auto IsChangingBrowsingMode = [&]() {
const bool willBeInPrivateBrowsingMode =
aPresContext && aPresContext->Document() &&
aPresContext->Document()->IsInPrivateBrowsing();
return willBeInPrivateBrowsingMode != aOldContext.mInPrivateBrowsing;
};
const auto IsChangingURI = [&]() {
const nsCOMPtr<nsIURI> newURI =
IMEStateManager::GetExposableURL(aPresContext);
if (!newURI != !aOldContext.mURI) {
return true; // One is not exposable URI.
}
if (!newURI) {
MOZ_ASSERT(!aOldContext.mURI);
return false; // Moved in non-exposable URIs.
}
bool same = false;
return NS_FAILED(newURI->Equals(aOldContext.mURI, &same)) || !same;
};
return !IsChangingBrowsingMode() && !IsChangingURI();
};
if (remoteHasFocus && XRE_IsParentProcess()) {
if (aAction.mFocusChange == InputContextAction::MENU_GOT_PSEUDO_FOCUS) {
// If menu keyboard listener is installed, we need to disable IME now.
@ -800,7 +823,8 @@ nsresult IMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
} else if (focusActuallyChanging) {
InputContext context = newWidget->GetInputContext();
if (context.mIMEState.mEnabled == IMEEnabled::Disabled &&
context.mOrigin == InputContext::ORIGIN_CONTENT) {
context.mOrigin == InputContext::ORIGIN_CONTENT &&
CanSkipSettingContext(context)) {
setIMEState = false;
MOZ_LOG(sISMLog, LogLevel::Debug,
(" OnChangeFocusInternal(), doesn't set IME state because "
@ -816,7 +840,8 @@ nsresult IMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
"focus actually"));
}
} else if (newWidget->GetInputContext().mOrigin !=
InputContext::ORIGIN_MAIN) {
InputContext::ORIGIN_MAIN &&
CanSkipSettingContext(newWidget->GetInputContext())) {
// When focus is NOT changed actually, we shouldn't set IME state if
// current input context was set by a remote process since that means
// that the window is being activated and the child process may have
@ -839,7 +864,8 @@ nsresult IMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
// actual focus isn't changing, but if IME enabled state is changing,
// we should do it.
InputContext context = newWidget->GetInputContext();
if (context.mIMEState.mEnabled == newState.mEnabled) {
if (context.mIMEState.mEnabled == newState.mEnabled &&
CanSkipSettingContext(context)) {
MOZ_LOG(sISMLog, LogLevel::Debug,
(" OnChangeFocusInternal(), neither focus nor IME state is "
"changing"));
@ -849,7 +875,7 @@ nsresult IMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
// Even if focus isn't changing actually, we should commit current
// composition here since the IME state is changing.
if (sFocusedPresContext && oldWidget && !focusActuallyChanging) {
if (sFocusedPresContext && oldWidget) {
NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, oldWidget,
sFocusedIMEBrowserParent);
}
@ -1929,6 +1955,48 @@ static bool GetAutocorrect(const IMEState& aState, const Element& aElement,
return true;
}
// static
already_AddRefed<nsIURI> IMEStateManager::GetExposableURL(
const nsPresContext* aPresContext) {
if (!aPresContext) {
return nullptr;
}
nsIURI* uri = aPresContext->Document()->GetDocumentURI();
if (!uri) {
return nullptr;
}
// We don't need to and should not expose special URLs such as:
// about: Any apps like IME should work normally and constantly in any
// default pages such as about:blank, about:home, etc in either
// the main process or a content process.
// blob: This may contain big data. If we copy it to the main process,
// it may make the heap dirty which makes the process slower.
// chrome: Same as about, any apps should work normally and constantly in
// any chrome documents.
// data: Any native apps in the environment shouldn't change the behavior
// with the data URL's content and it may contain too big data.
// file: The file path may contain private things and we shouldn't let
// other apps like IME know which one is touched by the user because
// malicious text services may like files which are explicitly used
// by the user better.
if (!net::SchemeIsHttpOrHttps(uri)) {
return nullptr;
}
// Note that we don't need to expose UserPass, Query and Reference to
// IME since they may contain sensitive data, but non-malicious text
// services must not require these data.
nsCOMPtr<nsIURI> exposableURL;
if (NS_FAILED(NS_MutateURI(uri)
.SetQuery(""_ns)
.SetRef(""_ns)
.SetUserPass(""_ns)
.Finalize(exposableURL))) {
return nullptr;
}
return exposableURL.forget();
}
// static
void IMEStateManager::SetIMEState(const IMEState& aState,
const nsPresContext* aPresContext,
@ -1946,37 +2014,7 @@ void IMEStateManager::SetIMEState(const IMEState& aState,
InputContext context;
context.mIMEState = aState;
if (aPresContext) {
if (nsIURI* uri = aPresContext->Document()->GetDocumentURI()) {
// We don't need to and should not expose special URLs such as:
// about: Any apps like IME should work normally and constantly in any
// default pages such as about:blank, about:home, etc in either
// the main process or a content process.
// blob: This may contain big data. If we copy it to the main process,
// it may make the heap dirty which makes the process slower.
// chrome: Same as about, any apps should work normally and constantly in
// any chrome documents.
// data: Any native apps in the environment shouldn't change the behavior
// with the data URL's content and it may contain too big data.
// file: The file path may contain private things and we shouldn't let
// other apps like IME know which one is touched by the user because
// malicious text services may like files which are explicitly used
// by the user better.
if (uri->SchemeIs("http") || uri->SchemeIs("https")) {
// Note that we don't need to expose UserPass, Query and Reference to
// IME since they may contain sensitive data, but non-malicious text
// services must not require these data.
nsCOMPtr<nsIURI> exposableURL;
if (NS_SUCCEEDED(NS_MutateURI(uri)
.SetQuery(""_ns)
.SetRef(""_ns)
.SetUserPass(""_ns)
.Finalize(exposableURL))) {
context.mURI = std::move(exposableURL);
}
}
}
}
context.mURI = IMEStateManager::GetExposableURL(aPresContext);
context.mOrigin = aOrigin;
context.mHasHandledUserInput =

View file

@ -7,6 +7,7 @@
#ifndef mozilla_IMEStateManager_h_
#define mozilla_IMEStateManager_h_
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/EventForwards.h"
#include "mozilla/Maybe.h"
#include "mozilla/StaticPtr.h"
@ -15,6 +16,7 @@
class nsIContent;
class nsINode;
class nsIURI;
class nsPresContext;
namespace mozilla {
@ -357,6 +359,13 @@ class IMEStateManager {
static IMEState GetNewIMEState(const nsPresContext& aPresContext,
dom::Element* aElement);
/**
* Return a URI which is exposable via the native IME API to the system or
* IME.
*/
static already_AddRefed<nsIURI> GetExposableURL(
const nsPresContext* aPresContext);
static void EnsureTextCompositionArray();
// XXX Changing this to MOZ_CAN_RUN_SCRIPT requires too many callers to be

View file

@ -247,8 +247,7 @@ class HTMLMediaElement::EventBlocker final : public nsISupports {
MOZ_ASSERT(mShouldBlockEventDelivery);
MOZ_ASSERT(mElement);
LOG_EVENT(LogLevel::Debug,
("%p postpone runner %s for %s", mElement.get(),
NS_ConvertUTF16toUTF8(aRunner->Name()).get(),
("%p postpone runner %s for %s", mElement.get(), aRunner->Name(),
NS_ConvertUTF16toUTF8(aRunner->EventName()).get()));
mPendingEventRunners.AppendElement(aRunner);
}
@ -282,8 +281,7 @@ class HTMLMediaElement::EventBlocker final : public nsISupports {
MOZ_ASSERT(mElement);
for (auto& runner : mPendingEventRunners) {
LOG_EVENT(LogLevel::Debug,
("%p execute runner %s for %s", mElement.get(),
NS_ConvertUTF16toUTF8(runner->Name()).get(),
("%p execute runner %s for %s", mElement.get(), runner->Name(),
NS_ConvertUTF16toUTF8(runner->EventName()).get()));
GetMainThreadSerialEventTarget()->Dispatch(runner.forget());
}
@ -2014,24 +2012,31 @@ class HTMLMediaElement::ErrorSink {
}
ReportErrorProbe(aErrorCode, aResult);
mError = new MediaError(mOwner, aErrorCode,
aResult ? aResult->Message() : nsCString());
mOwner->DispatchAsyncEvent(u"error"_ns);
if (mOwner->ReadyState() == HAVE_NOTHING &&
aErrorCode == MEDIA_ERR_ABORTED) {
// https://html.spec.whatwg.org/multipage/embedded-content.html#media-data-processing-steps-list
// https://html.spec.whatwg.org/multipage/media.html#media-data-processing-steps-list
// "If the media data fetching process is aborted by the user"
mOwner->DispatchAsyncEvent(u"abort"_ns);
mOwner->QueueEvent(u"abort"_ns);
mOwner->ChangeNetworkState(NETWORK_EMPTY);
mOwner->DispatchAsyncEvent(u"emptied"_ns);
mOwner->QueueEvent(u"emptied"_ns);
if (mOwner->mDecoder) {
mOwner->ShutdownDecoder();
}
} else if (aErrorCode == MEDIA_ERR_SRC_NOT_SUPPORTED) {
return;
}
if (aErrorCode == MEDIA_ERR_SRC_NOT_SUPPORTED) {
// https://html.spec.whatwg.org/multipage/media.html#dedicated-media-source-failure-steps
mOwner->ChangeNetworkState(NETWORK_NO_SOURCE);
} else {
// https://html.spec.whatwg.org/multipage/media.html#media-data-processing-steps-list
// "If the connection is interrupted after some media data has been
// received" or "If the media data is corrupted"
mOwner->ChangeNetworkState(NETWORK_IDLE);
}
mError = new MediaError(mOwner, aErrorCode,
aResult ? aResult->Message() : nsCString());
mOwner->QueueEvent(u"error"_ns);
}
void ResetError() { mError = nullptr; }
@ -2459,7 +2464,7 @@ void HTMLMediaElement::AbortExistingLoads() {
mMediaSource = nullptr;
if (mNetworkState == NETWORK_LOADING || mNetworkState == NETWORK_IDLE) {
DispatchAsyncEvent(u"abort"_ns);
QueueEvent(u"abort"_ns);
}
bool hadVideo = HasVideo();
@ -2488,7 +2493,7 @@ void HTMLMediaElement::AbortExistingLoads() {
NS_ASSERTION(!mDecoder && !mSrcStream,
"How did someone setup a new stream/decoder already?");
DispatchAsyncEvent(u"emptied"_ns);
QueueEvent(u"emptied"_ns);
// ChangeNetworkState() will call UpdateAudioChannelPlayingState()
// indirectly which depends on mPaused. So we need to update mPaused first.
@ -2743,7 +2748,7 @@ void HTMLMediaElement::SelectResource() {
ChangeDelayLoadStatus(true);
ChangeNetworkState(NETWORK_LOADING);
DispatchAsyncEvent(u"loadstart"_ns);
QueueEvent(u"loadstart"_ns);
// Delay setting mIsRunningSeletResource until after UpdatePreloadAction
// so that we don't lose our state change by bailing out of the preload
@ -2804,23 +2809,7 @@ void HTMLMediaElement::SelectResource() {
ReportLoadError("MediaLoadInvalidURI", params);
rv = MediaResult(rv.Code(), "MediaLoadInvalidURI");
}
// https://html.spec.whatwg.org/multipage/media.html#concept-media-load-algorithm
// "Failed with attribute:"
// "Take pending play promises and queue a media element task given the
// media element to run the dedicated media source failure steps with the
// result."
GetMainThreadSerialEventTarget()->Dispatch(NS_NewRunnableFunction(
"HTMLMediaElement::NoSupportedMediaSourceError",
[this, self = RefPtr{this}, loadId = GetCurrentLoadID(),
description = rv.Description()]() {
// Drop the task if the load algorithm has been invoked again.
// https://html.spec.whatwg.org/multipage/media.html#media-element-load-algorithm
// "Remove each task in pending tasks from its task queue."
if (GetCurrentLoadID() == loadId) {
// The failed load has not been aborted.
NoSupportedMediaSourceError(description);
}
}));
NoSupportedMediaSourceError(rv.Description());
} else {
// Otherwise, the source elements will be used.
mIsLoadingFromSourceChildren = true;
@ -3312,7 +3301,7 @@ nsresult HTMLMediaElement::LoadWithChannel(nsIChannel* aChannel,
}
SetPlaybackRate(mDefaultPlaybackRate, IgnoreErrors());
DispatchAsyncEvent(u"loadstart"_ns);
QueueEvent(u"loadstart"_ns);
return NS_OK;
}
@ -3595,7 +3584,7 @@ void HTMLMediaElement::PauseInternal() {
if (!oldPaused) {
FireTimeUpdate(TimeupdateType::eMandatory);
DispatchAsyncEvent(u"pause"_ns);
QueueEvent(u"pause"_ns);
AsyncRejectPendingPlayPromises(NS_ERROR_DOM_MEDIA_ABORT_ERR);
}
}
@ -3615,7 +3604,7 @@ void HTMLMediaElement::SetVolume(double aVolume, ErrorResult& aRv) {
// Here we want just to update the volume.
SetVolumeInternal();
DispatchAsyncEvent(u"volumechange"_ns);
QueueEvent(u"volumechange"_ns);
// We allow inaudible autoplay. But changing our volume may make this
// media audible. So pause if we are no longer supposed to be autoplaying.
@ -3700,7 +3689,7 @@ void HTMLMediaElement::SetMuted(bool aMuted) {
SetMutedInternal(mMuted & ~MUTED_BY_CONTENT);
}
DispatchAsyncEvent(u"volumechange"_ns);
QueueEvent(u"volumechange"_ns);
// We allow inaudible autoplay. But changing our mute status may make this
// media audible. So pause if we are no longer supposed to be autoplaying.
@ -4654,7 +4643,7 @@ already_AddRefed<Promise> HTMLMediaElement::Play(ErrorResult& aRv) {
void HTMLMediaElement::DispatchEventsWhenPlayWasNotAllowed() {
if (StaticPrefs::media_autoplay_block_event_enabled()) {
DispatchAsyncEvent(u"blocked"_ns);
QueueEvent(u"blocked"_ns);
}
DispatchBlockEventForVideoControl();
if (!mHasEverBeenBlockedForAutoplay) {
@ -4766,7 +4755,7 @@ void HTMLMediaElement::PlayInternal(bool aHandlingUserInput) {
}
// 6.3. Queue a task to fire a simple event named play at the element.
DispatchAsyncEvent(u"play"_ns);
QueueEvent(u"play"_ns);
// 6.4. If the media element's readyState attribute has the value
// HAVE_NOTHING, HAVE_METADATA, or HAVE_CURRENT_DATA, queue a task to
@ -4776,11 +4765,11 @@ void HTMLMediaElement::PlayInternal(bool aHandlingUserInput) {
// element.
switch (mReadyState) {
case HAVE_NOTHING:
DispatchAsyncEvent(u"waiting"_ns);
QueueEvent(u"waiting"_ns);
break;
case HAVE_METADATA:
case HAVE_CURRENT_DATA:
DispatchAsyncEvent(u"waiting"_ns);
QueueEvent(u"waiting"_ns);
break;
case HAVE_FUTURE_DATA:
case HAVE_ENOUGH_DATA:
@ -5650,16 +5639,16 @@ void HTMLMediaElement::MetadataLoaded(const MediaInfo* aInfo,
// "loadedmetadata" event handlers.
UpdateOutputTrackSources();
DispatchAsyncEvent(u"durationchange"_ns);
QueueEvent(u"durationchange"_ns);
if (IsVideo() && HasVideo()) {
DispatchAsyncEvent(u"resize"_ns);
QueueEvent(u"resize"_ns);
Invalidate(ImageSizeChanged::No, Some(mMediaInfo.mVideo.mDisplay),
ForceInvalidate::No);
}
NS_ASSERTION(!HasVideo() || (mMediaInfo.mVideo.mDisplay.width > 0 &&
mMediaInfo.mVideo.mDisplay.height > 0),
"Video resolution must be known on 'loadedmetadata'");
DispatchAsyncEvent(u"loadedmetadata"_ns);
QueueEvent(u"loadedmetadata"_ns);
if (mDecoder && mDecoder->IsTransportSeekable() &&
mDecoder->IsMediaSeekable()) {
@ -5783,7 +5772,7 @@ void HTMLMediaElement::PlaybackEnded() {
LOG(LogLevel::Debug,
("%p, got duration by reaching the end of the resource", this));
mSrcStreamPlaybackEnded = true;
DispatchAsyncEvent(u"durationchange"_ns);
QueueEvent(u"durationchange"_ns);
} else {
// mediacapture-main:
// Setting the loop attribute has no effect since a MediaStream has no
@ -5809,14 +5798,14 @@ void HTMLMediaElement::PlaybackEnded() {
if (StaticPrefs::media_mediacontrol_stopcontrol_aftermediaends()) {
mMediaControlKeyListener->StopIfNeeded();
}
DispatchAsyncEvent(u"ended"_ns);
QueueEvent(u"ended"_ns);
}
void HTMLMediaElement::UpdateSrcStreamReportPlaybackEnded() {
mSrcStreamReportPlaybackEnded = mSrcStreamPlaybackEnded;
}
void HTMLMediaElement::SeekStarted() { DispatchAsyncEvent(u"seeking"_ns); }
void HTMLMediaElement::SeekStarted() { QueueEvent(u"seeking"_ns); }
void HTMLMediaElement::SeekCompleted() {
mPlayingBeforeSeek = false;
@ -5828,7 +5817,7 @@ void HTMLMediaElement::SeekCompleted() {
// (Step 16)
// TODO (bug 1688131): run these steps in a stable state.
FireTimeUpdate(TimeupdateType::eMandatory);
DispatchAsyncEvent(u"seeked"_ns);
QueueEvent(u"seeked"_ns);
// We changed whether we're seeking so we need to AddRemoveSelfReference
AddRemoveSelfReference();
if (mCurrentPlayRangeStart == -1.0) {
@ -5862,7 +5851,7 @@ void HTMLMediaElement::NotifySuspendedByCache(bool aSuspendedByCache) {
void HTMLMediaElement::DownloadSuspended() {
if (mNetworkState == NETWORK_LOADING) {
DispatchAsyncEvent(u"progress"_ns);
QueueEvent(u"progress"_ns);
}
ChangeNetworkState(NETWORK_IDLE);
}
@ -5892,7 +5881,7 @@ void HTMLMediaElement::CheckProgress(bool aHaveNewProgress) {
: (now - mProgressTime >=
TimeDuration::FromMilliseconds(PROGRESS_MS) &&
mDataTime > mProgressTime)) {
DispatchAsyncEvent(u"progress"_ns);
QueueEvent(u"progress"_ns);
// Resolution() ensures that future data will have now > mProgressTime,
// and so will trigger another event. mDataTime is not reset because it
// is still required to detect stalled; it is similarly offset by
@ -5917,7 +5906,7 @@ void HTMLMediaElement::CheckProgress(bool aHaveNewProgress) {
if (now - mDataTime >= TimeDuration::FromMilliseconds(STALL_MS)) {
if (!mMediaSource) {
DispatchAsyncEvent(u"stalled"_ns);
QueueEvent(u"stalled"_ns);
} else {
ChangeDelayLoadStatus(false);
}
@ -6077,7 +6066,7 @@ void HTMLMediaElement::UpdateReadyStateInternal() {
// Note: Playback will already be stalled, as the next frame is
// unavailable.
mWaitingForKey = WAITING_FOR_KEY_DISPATCHED;
DispatchAsyncEvent(u"waitingforkey"_ns);
QueueEvent(u"waitingforkey"_ns);
}
} else {
MOZ_ASSERT(mWaitingForKey == WAITING_FOR_KEY_DISPATCHED);
@ -6227,21 +6216,21 @@ void HTMLMediaElement::ChangeReadyState(nsMediaReadyState aState) {
// must queue a task to fire a simple event named timeupdate at the element,
// and queue a task to fire a simple event named waiting at the element."
if (mPlayingBeforeSeek && mReadyState < HAVE_FUTURE_DATA) {
DispatchAsyncEvent(u"waiting"_ns);
QueueEvent(u"waiting"_ns);
} else if (oldState >= HAVE_FUTURE_DATA && mReadyState < HAVE_FUTURE_DATA &&
!Paused() && !Ended() && !mErrorSink->mError) {
FireTimeUpdate(TimeupdateType::eMandatory);
DispatchAsyncEvent(u"waiting"_ns);
QueueEvent(u"waiting"_ns);
}
if (oldState < HAVE_CURRENT_DATA && mReadyState >= HAVE_CURRENT_DATA &&
!mLoadedDataFired) {
DispatchAsyncEvent(u"loadeddata"_ns);
QueueEvent(u"loadeddata"_ns);
mLoadedDataFired = true;
}
if (oldState < HAVE_FUTURE_DATA && mReadyState >= HAVE_FUTURE_DATA) {
DispatchAsyncEvent(u"canplay"_ns);
QueueEvent(u"canplay"_ns);
if (!mPaused) {
if (mDecoder && !mSuspendedByInactiveDocOrDocshell) {
MOZ_ASSERT(AllowedToPlay());
@ -6254,7 +6243,7 @@ void HTMLMediaElement::ChangeReadyState(nsMediaReadyState aState) {
CheckAutoplayDataReady();
if (oldState < HAVE_ENOUGH_DATA && mReadyState >= HAVE_ENOUGH_DATA) {
DispatchAsyncEvent(u"canplaythrough"_ns);
QueueEvent(u"canplaythrough"_ns);
}
}
@ -6283,7 +6272,7 @@ void HTMLMediaElement::ChangeNetworkState(nsMediaNetworkState aState) {
StartProgress();
} else if (mNetworkState == NETWORK_IDLE && !mErrorSink->mError) {
// Fire 'suspend' event when entering NETWORK_IDLE and no error presented.
DispatchAsyncEvent(u"suspend"_ns);
QueueEvent(u"suspend"_ns);
}
// According to the resource selection (step2, step9-18), dedicated media
@ -6382,9 +6371,9 @@ void HTMLMediaElement::RunAutoplay() {
}
// For blocked media, the event would be pending until it is resumed.
DispatchAsyncEvent(u"play"_ns);
QueueEvent(u"play"_ns);
DispatchAsyncEvent(u"playing"_ns);
QueueEvent(u"playing"_ns);
MaybeMarkSHEntryAsUserInteracted();
}
@ -6504,26 +6493,26 @@ already_AddRefed<nsMediaEventRunner> HTMLMediaElement::GetEventRunner(
return runner.forget();
}
nsresult HTMLMediaElement::DispatchEvent(const nsAString& aName) {
LOG_EVENT(LogLevel::Debug, ("%p Dispatching event %s", this,
NS_ConvertUTF16toUTF8(aName).get()));
nsresult HTMLMediaElement::FireEvent(const nsAString& aName) {
if (mEventBlocker->ShouldBlockEventDelivery()) {
RefPtr<nsMediaEventRunner> runner = GetEventRunner(aName);
mEventBlocker->PostponeEvent(runner);
return NS_OK;
}
LOG_EVENT(LogLevel::Debug,
("%p Firing event %s", this, NS_ConvertUTF16toUTF8(aName).get()));
return nsContentUtils::DispatchTrustedEvent(OwnerDoc(), this, aName,
CanBubble::eNo, Cancelable::eNo);
}
void HTMLMediaElement::DispatchAsyncEvent(const nsAString& aName) {
void HTMLMediaElement::QueueEvent(const nsAString& aName) {
RefPtr<nsMediaEventRunner> runner = GetEventRunner(aName);
DispatchAsyncEvent(std::move(runner));
QueueTask(std::move(runner));
}
void HTMLMediaElement::DispatchAsyncEvent(RefPtr<nsMediaEventRunner> aRunner) {
void HTMLMediaElement::QueueTask(RefPtr<nsMediaEventRunner> aRunner) {
NS_ConvertUTF16toUTF8 eventName(aRunner->EventName());
LOG_EVENT(LogLevel::Debug, ("%p Queuing event %s", this, eventName.get()));
DDLOG(DDLogCategory::Event, "HTMLMediaElement", nsCString(eventName.get()));
@ -6640,7 +6629,7 @@ void HTMLMediaElement::UpdateMediaSize(const nsIntSize& aSize) {
if (IsVideo() && mReadyState != HAVE_NOTHING &&
mMediaInfo.mVideo.mDisplay != aSize) {
DispatchAsyncEvent(u"resize"_ns);
QueueEvent(u"resize"_ns);
}
mMediaInfo.mVideo.mDisplay = aSize;
@ -6964,7 +6953,7 @@ void HTMLMediaElement::FireTimeUpdate(TimeupdateType aType) {
GetEventRunner(u"timeupdate"_ns, aType == TimeupdateType::eMandatory
? EventFlag::eMandatory
: EventFlag::eNone);
DispatchAsyncEvent(std::move(runner));
QueueTask(std::move(runner));
mQueueTimeUpdateRunnerTime = TimeStamp::Now();
mLastCurrentTime = CurrentTime();
}
@ -7029,7 +7018,7 @@ void HTMLMediaElement::SetDefaultPlaybackRate(double aDefaultPlaybackRate,
}
mDefaultPlaybackRate = defaultPlaybackRate;
DispatchAsyncEvent(u"ratechange"_ns);
QueueEvent(u"ratechange"_ns);
}
void HTMLMediaElement::SetPlaybackRate(double aPlaybackRate, ErrorResult& aRv) {
@ -7061,7 +7050,7 @@ void HTMLMediaElement::SetPlaybackRate(double aPlaybackRate, ErrorResult& aRv) {
if (mDecoder) {
mDecoder->SetPlaybackRate(ClampPlaybackRate(mPlaybackRate));
}
DispatchAsyncEvent(u"ratechange"_ns);
QueueEvent(u"ratechange"_ns);
mMediaControlKeyListener->NotifyMediaPositionState();
}
@ -7105,7 +7094,7 @@ void HTMLMediaElement::OnVisibilityChange(Visibility aNewVisibility) {
mVisibilityState = aNewVisibility;
if (StaticPrefs::media_test_video_suspend()) {
DispatchAsyncEvent(u"visibilitychanged"_ns);
QueueEvent(u"visibilitychanged"_ns);
}
if (!mDecoder) {
@ -7552,7 +7541,7 @@ void HTMLMediaElement::DispatchAsyncTestingEvent(const nsAString& aName) {
if (!StaticPrefs::media_testing_only_events()) {
return;
}
DispatchAsyncEvent(aName);
QueueEvent(aName);
}
void HTMLMediaElement::AudioCaptureTrackChange(bool aCapture) {
@ -7632,9 +7621,9 @@ nsTArray<RefPtr<PlayPromise>> HTMLMediaElement::TakePendingPlayPromises() {
}
void HTMLMediaElement::NotifyAboutPlaying() {
// Stick to the DispatchAsyncEvent() call path for now because we want to
// trigger some telemetry-related codes in the DispatchAsyncEvent() method.
DispatchAsyncEvent(u"playing"_ns);
// Stick to the QueueEvent() call path for now because we want to
// trigger some telemetry-related codes in the QueueEvent() method.
QueueEvent(u"playing"_ns);
}
already_AddRefed<PlayPromise> HTMLMediaElement::CreatePlayPromise(
@ -7678,7 +7667,7 @@ void HTMLMediaElement::AsyncResolvePendingPlayPromises() {
void HTMLMediaElement::AsyncRejectPendingPlayPromises(nsresult aError) {
if (!mPaused) {
mPaused = true;
DispatchAsyncEvent(u"pause"_ns);
QueueEvent(u"pause"_ns);
}
if (mShuttingDown) {

View file

@ -310,9 +310,11 @@ class HTMLMediaElement : public nsGenericHTMLElement,
VideoFrameContainer* aContainer,
const PrincipalHandle& aNewPrincipalHandle) override;
// Dispatch events
void DispatchAsyncEvent(const nsAString& aName) final;
void DispatchAsyncEvent(RefPtr<nsMediaEventRunner> aRunner);
// Queue a media element task to fire an event targeted at the media element.
void QueueEvent(const nsAString& aName) final;
// Queue a media element task.
// The task is blocked while the document is in B/F cache.
void QueueTask(RefPtr<nsMediaEventRunner> aRunner);
// Triggers a recomputation of readyState.
void UpdateReadyState() override {
@ -1077,8 +1079,7 @@ class HTMLMediaElement : public nsGenericHTMLElement,
* state to NETWORK_NO_SOURCE, and sends error event with code
* MEDIA_ERR_SRC_NOT_SUPPORTED.
*/
void NoSupportedMediaSourceError(
const nsACString& aErrorDetails = nsCString());
void NoSupportedMediaSourceError(const nsACString& aErrorDetails);
/**
* Per spec, Failed with elements: Queue a task, using the DOM manipulation
@ -1324,7 +1325,8 @@ class HTMLMediaElement : public nsGenericHTMLElement,
using nsGenericHTMLElement::DispatchEvent;
// For nsAsyncEventRunner.
nsresult DispatchEvent(const nsAString& aName);
// The event is blocked while the document is in B/F cache.
MOZ_CAN_RUN_SCRIPT nsresult FireEvent(const nsAString& aName);
already_AddRefed<nsMediaEventRunner> GetEventRunner(
const nsAString& aName, EventFlag aFlag = EventFlag::eNone);

View file

@ -148,6 +148,10 @@ interface nsIContentSecurityPolicy : nsISerializable
/*
* Whether this policy allows inline script or style.
*
* Reports when the policy forbids aContentOfPseudoScript, including
* potentially asynchronously firing a "securitypolicyviolation" event.
*
* @param aContentPolicyType Either SCRIPT_SRC_(ELEM|ATTR)_DIRECTIVE or
* STYLE_SRC_(ELEM|ATTR)_DIRECTIVE.
* @param aHasUnsafeHash Only hash this when the 'unsafe-hashes' directive is

View file

@ -3550,8 +3550,7 @@ nsresult BrowserChild::CanCancelContentJS(
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIURI> currentURI = entry->GetURI();
if (!currentURI->SchemeIs("http") && !currentURI->SchemeIs("https") &&
!currentURI->SchemeIs("file")) {
if (!net::SchemeIsHttpOrHttps(currentURI) && !currentURI->SchemeIs("file")) {
// Only cancel content JS for http(s) and file URIs. Other URIs are probably
// internal and we should just let them run to completion.
return NS_OK;

View file

@ -3746,8 +3746,7 @@ bool BrowserParent::CanCancelContentJS(
false);
nsCOMPtr<nsIURI> currentURI = entry->GetURI();
if (!currentURI->SchemeIs("http") && !currentURI->SchemeIs("https") &&
!currentURI->SchemeIs("file")) {
if (!net::SchemeIsHttpOrHttps(currentURI) && !currentURI->SchemeIs("file")) {
// Only cancel content JS for http(s) and file URIs. Other URIs are probably
// internal and we should just let them run to completion.
return false;

View file

@ -84,6 +84,7 @@
#include "mozilla/StyleSheetInlines.h"
#include "mozilla/TaskController.h"
#include "mozilla/glean/DomMetrics.h"
#include "mozilla/glean/IpcMetrics.h"
#include "mozilla/Telemetry.h"
#include "mozilla/TelemetryIPC.h"
#include "mozilla/ThreadSafety.h"
@ -1942,8 +1943,7 @@ void ContentParent::ActorDestroy(ActorDestroyReason why) {
if (StringBeginsWith(mRemoteType, WEB_REMOTE_TYPE) ||
mRemoteType == FILE_REMOTE_TYPE || mRemoteType == EXTENSION_REMOTE_TYPE) {
TimeDuration runtime = TimeStamp::Now() - mActivateTS;
Telemetry::Accumulate(Telemetry::PROCESS_LIFETIME,
uint64_t(runtime.ToSeconds()));
glean::process::lifetime.AccumulateRawDuration(runtime);
}
if (mSendShutdownTimer) {
@ -2007,8 +2007,7 @@ void ContentParent::ActorDestroy(ActorDestroyReason why) {
props->SetPropertyAsUint64(u"childID"_ns, mChildID);
if (AbnormalShutdown == why) {
Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT, "content"_ns,
1);
glean::subprocess::abnormal_abort.Get("content"_ns).Add(1);
props->SetPropertyAsBool(u"abnormal"_ns, true);
@ -4349,7 +4348,7 @@ void ContentParent::KillHard(const char* aReason) {
} else {
reason = nsDependentCString("KillHard after IsNotifiedShutdownSuccess.");
}
Telemetry::Accumulate(Telemetry::SUBPROCESS_KILL_HARD, reason, 1);
glean::subprocess::kill_hard.Get(reason).Add(1);
ProcessHandle otherProcessHandle;
if (!base::OpenProcessHandle(OtherPid(), &otherProcessHandle)) {

View file

@ -332,7 +332,7 @@ mozilla::ipc::IPCResult WindowGlobalParent::RecvLoadURI(
return IPC_OK();
}
if (net::SchemeIsJavascript(aLoadState->URI())) {
if (aLoadState->URI()->SchemeIs("javascript")) {
return IPC_FAIL(this, "Illegal cross-process javascript: load attempt");
}
@ -365,7 +365,7 @@ mozilla::ipc::IPCResult WindowGlobalParent::RecvInternalLoad(
return IPC_OK();
}
if (net::SchemeIsJavascript(aLoadState->URI())) {
if (aLoadState->URI()->SchemeIs("javascript")) {
return IPC_FAIL(this, "Illegal cross-process javascript: load attempt");
}
@ -1372,23 +1372,23 @@ mozilla::ipc::IPCResult WindowGlobalParent::RecvSetDocumentDomain(
mozilla::ipc::IPCResult WindowGlobalParent::RecvReloadWithHttpsOnlyException() {
nsresult rv;
nsCOMPtr<nsIURI> currentUri = BrowsingContext()->Top()->GetCurrentURI();
nsCOMPtr<nsIURI> currentURI = BrowsingContext()->Top()->GetCurrentURI();
if (!currentUri) {
if (!currentURI) {
return IPC_FAIL(this, "HTTPS-only mode: Failed to get current URI");
}
bool isViewSource = currentUri->SchemeIs("view-source");
bool isViewSource = currentURI->SchemeIs("view-source");
nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(currentUri);
nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(currentURI);
nsCOMPtr<nsIURI> innerURI;
if (isViewSource) {
nestedURI->GetInnerURI(getter_AddRefs(innerURI));
} else {
innerURI = currentUri;
innerURI = currentURI;
}
if (!innerURI->SchemeIs("https") && !innerURI->SchemeIs("http")) {
if (!net::SchemeIsHttpOrHttps(innerURI)) {
return IPC_FAIL(this, "HTTPS-only mode: Illegal state");
}
@ -1641,8 +1641,7 @@ void WindowGlobalParent::ActorDestroy(ActorDestroyReason aWhy) {
BrowsingContext()->IsTopContent()) {
GetContentBlockingLog()->ReportLog();
if (mDocumentURI && (net::SchemeIsHTTP(mDocumentURI) ||
net::SchemeIsHTTPS(mDocumentURI))) {
if (mDocumentURI && net::SchemeIsHttpOrHttps(mDocumentURI)) {
GetContentBlockingLog()->ReportCanvasFingerprintingLog(
DocumentPrincipal());
GetContentBlockingLog()->ReportFontFingerprintingLog(

View file

@ -63,14 +63,18 @@ using mozilla::dom::AutoEntryScript;
static NS_DEFINE_CID(kJSURICID, NS_JSURI_CID);
class nsJSThunk : public nsIInputStream {
// A stream class used to handle javascript: URLs.
class JSURLInputStream : public nsIInputStream {
public:
nsJSThunk();
JSURLInputStream();
NS_DECL_THREADSAFE_ISUPPORTS
NS_FORWARD_SAFE_NSIINPUTSTREAM(mInnerStream)
nsresult Init(nsIURI* uri);
// @param aExecutionPolicy `nsIScriptChannel::NO_EXECUTION` or
// `nsIScriptChannel::EXECUTE_NORMAL`.
nsresult EvaluateScript(
nsIChannel* aChannel,
mozilla::dom::PopupBlocker::PopupControlState aPopupState,
@ -78,7 +82,7 @@ class nsJSThunk : public nsIInputStream {
const mozilla::JSCallingLocation& aJSCallingLocation);
protected:
virtual ~nsJSThunk();
virtual ~JSURLInputStream();
nsCOMPtr<nsIInputStream> mInnerStream;
nsCString mScript;
@ -88,13 +92,13 @@ class nsJSThunk : public nsIInputStream {
//
// nsISupports implementation...
//
NS_IMPL_ISUPPORTS(nsJSThunk, nsIInputStream)
NS_IMPL_ISUPPORTS(JSURLInputStream, nsIInputStream)
nsJSThunk::nsJSThunk() = default;
JSURLInputStream::JSURLInputStream() = default;
nsJSThunk::~nsJSThunk() = default;
JSURLInputStream::~JSURLInputStream() = default;
nsresult nsJSThunk::Init(nsIURI* uri) {
nsresult JSURLInputStream::Init(nsIURI* uri) {
NS_ENSURE_ARG_POINTER(uri);
// Get the script string to evaluate...
@ -135,6 +139,9 @@ static nsIScriptGlobalObject* GetGlobalObject(nsIChannel* aChannel) {
return global;
}
// https://w3c.github.io/webappsec-csp/#should-block-navigation-request
// specialized for type "navigation" requests with "javascript: URLs".
// Excluding step 2.
static bool AllowedByCSP(nsIContentSecurityPolicy* aCSP,
const nsACString& aJavaScriptURL,
const mozilla::JSCallingLocation& aJSCallingLocation) {
@ -142,7 +149,6 @@ static bool AllowedByCSP(nsIContentSecurityPolicy* aCSP,
return true;
}
// https://w3c.github.io/webappsec-csp/#should-block-navigation-request
// Step 3. If result is "Allowed", and if navigation requests current URLs
// scheme is javascript:
//
@ -230,7 +236,7 @@ static void ExecScriptAndCoerceToString(JSContext* aCx,
}
}
nsresult nsJSThunk::EvaluateScript(
nsresult JSURLInputStream::EvaluateScript(
nsIChannel* aChannel,
mozilla::dom::PopupBlocker::PopupControlState aPopupState,
uint32_t aExecutionPolicy, nsPIDOMWindowInner* aOriginalInnerWindow,
@ -505,7 +511,7 @@ class nsJSChannel : public nsIChannel,
nsLoadFlags mLoadFlags;
nsLoadFlags mActualLoadFlags; // See AsyncOpen
RefPtr<nsJSThunk> mIOThunk;
RefPtr<JSURLInputStream> mJSURIStream;
mozilla::dom::PopupBlocker::PopupControlState mPopupState;
mozilla::JSCallingLocation mJSCallingLocation;
uint32_t mExecutionPolicy;
@ -545,19 +551,19 @@ nsresult nsJSChannel::Init(nsIURI* aURI, nsILoadInfo* aLoadInfo) {
NS_ENSURE_SUCCESS(rv, rv);
// Create the nsIStreamIO layer used by the nsIStreamIOChannel.
mIOThunk = new nsJSThunk();
mJSURIStream = new JSURLInputStream();
// Create a stock input stream channel...
// Remember, until AsyncOpen is called, the script will not be evaluated
// and the underlying Input Stream will not be created...
nsCOMPtr<nsIChannel> channel;
RefPtr<nsJSThunk> thunk = mIOThunk;
RefPtr<JSURLInputStream> jsURIStream = mJSURIStream;
rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel), aURI,
thunk.forget(), "text/html"_ns, ""_ns,
aLoadInfo);
jsURIStream.forget(), "text/html"_ns,
""_ns, aLoadInfo);
NS_ENSURE_SUCCESS(rv, rv);
rv = mIOThunk->Init(aURI);
rv = mJSURIStream->Init(aURI);
if (NS_SUCCEEDED(rv)) {
mStreamChannel = channel;
mPropertyBag = do_QueryInterface(channel);
@ -672,8 +678,9 @@ nsJSChannel::Open(nsIInputStream** aStream) {
NS_ENSURE_SUCCESS(rv, rv);
mJSCallingLocation = mozilla::JSCallingLocation::Get();
rv = mIOThunk->EvaluateScript(mStreamChannel, mPopupState, mExecutionPolicy,
mOriginalInnerWindow, mJSCallingLocation);
rv = mJSURIStream->EvaluateScript(mStreamChannel, mPopupState,
mExecutionPolicy, mOriginalInnerWindow,
mJSCallingLocation);
NS_ENSURE_SUCCESS(rv, rv);
return mStreamChannel->Open(aStream);
@ -822,9 +829,9 @@ void nsJSChannel::EvaluateScript() {
// script returns it).
if (NS_SUCCEEDED(mStatus)) {
nsresult rv =
mIOThunk->EvaluateScript(mStreamChannel, mPopupState, mExecutionPolicy,
mOriginalInnerWindow, mJSCallingLocation);
nsresult rv = mJSURIStream->EvaluateScript(
mStreamChannel, mPopupState, mExecutionPolicy, mOriginalInnerWindow,
mJSCallingLocation);
// Note that evaluation may have canceled us, so recheck mStatus again
if (NS_FAILED(rv) && NS_SUCCEEDED(mStatus)) {

View file

@ -371,24 +371,24 @@ void MediaDecoder::OnPlaybackEvent(MediaPlaybackEvent&& aEvent) {
Invalidate();
break;
case MediaPlaybackEvent::EnterVideoSuspend:
GetOwner()->DispatchAsyncEvent(u"mozentervideosuspend"_ns);
GetOwner()->QueueEvent(u"mozentervideosuspend"_ns);
mIsVideoDecodingSuspended = true;
break;
case MediaPlaybackEvent::ExitVideoSuspend:
GetOwner()->DispatchAsyncEvent(u"mozexitvideosuspend"_ns);
GetOwner()->QueueEvent(u"mozexitvideosuspend"_ns);
mIsVideoDecodingSuspended = false;
break;
case MediaPlaybackEvent::StartVideoSuspendTimer:
GetOwner()->DispatchAsyncEvent(u"mozstartvideosuspendtimer"_ns);
GetOwner()->QueueEvent(u"mozstartvideosuspendtimer"_ns);
break;
case MediaPlaybackEvent::CancelVideoSuspendTimer:
GetOwner()->DispatchAsyncEvent(u"mozcancelvideosuspendtimer"_ns);
GetOwner()->QueueEvent(u"mozcancelvideosuspendtimer"_ns);
break;
case MediaPlaybackEvent::VideoOnlySeekBegin:
GetOwner()->DispatchAsyncEvent(u"mozvideoonlyseekbegin"_ns);
GetOwner()->QueueEvent(u"mozvideoonlyseekbegin"_ns);
break;
case MediaPlaybackEvent::VideoOnlySeekCompleted:
GetOwner()->DispatchAsyncEvent(u"mozvideoonlyseekcompleted"_ns);
GetOwner()->QueueEvent(u"mozvideoonlyseekcompleted"_ns);
break;
default:
break;
@ -401,15 +401,20 @@ bool MediaDecoder::IsVideoDecodingSuspended() const {
void MediaDecoder::OnPlaybackErrorEvent(const MediaResult& aError) {
MOZ_ASSERT(NS_IsMainThread());
#ifndef MOZ_WMF_MEDIA_ENGINE
DecodeError(aError);
#else
if (aError != NS_ERROR_DOM_MEDIA_EXTERNAL_ENGINE_NOT_SUPPORTED_ERR &&
aError != NS_ERROR_DOM_MEDIA_CDM_PROXY_NOT_SUPPORTED_ERR) {
DecodeError(aError);
#ifdef MOZ_WMF_MEDIA_ENGINE
if (aError == NS_ERROR_DOM_MEDIA_EXTERNAL_ENGINE_NOT_SUPPORTED_ERR ||
aError == NS_ERROR_DOM_MEDIA_CDM_PROXY_NOT_SUPPORTED_ERR) {
SwitchStateMachine(aError);
return;
}
#endif
DecodeError(aError);
}
#ifdef MOZ_WMF_MEDIA_ENGINE
void MediaDecoder::SwitchStateMachine(const MediaResult& aError) {
MOZ_ASSERT(aError == NS_ERROR_DOM_MEDIA_EXTERNAL_ENGINE_NOT_SUPPORTED_ERR ||
aError == NS_ERROR_DOM_MEDIA_CDM_PROXY_NOT_SUPPORTED_ERR);
// Already in shutting down decoder, no need to create another state machine.
if (mPlayState == PLAY_STATE_SHUTDOWN) {
return;
@ -491,8 +496,8 @@ void MediaDecoder::OnPlaybackErrorEvent(const MediaResult& aError) {
discardStateMachine->BeginShutdown()->Then(
AbstractThread::MainThread(), __func__, [discardStateMachine] {});
#endif
}
#endif
void MediaDecoder::OnDecoderDoctorEvent(DecoderDoctorEvent aEvent) {
MOZ_ASSERT(NS_IsMainThread());
@ -1147,7 +1152,7 @@ void MediaDecoder::DurationChanged() {
if (mFiredMetadataLoaded &&
(!std::isinf(mDuration.match(DurationToDouble())) ||
mExplicitDuration.isSome())) {
GetOwner()->DispatchAsyncEvent(u"durationchange"_ns);
GetOwner()->QueueEvent(u"durationchange"_ns);
}
if (CurrentPosition().ToSeconds() > mDuration.match(DurationToDouble())) {
@ -1548,7 +1553,7 @@ RefPtr<SetCDMPromise> MediaDecoder::SetCDMProxy(CDMProxy* aProxy) {
// given CDM proxy.
if (aProxy && !GetStateMachine()->IsCDMProxySupported(aProxy)) {
LOG("CDM proxy not supported! Switch to another state machine.");
OnPlaybackErrorEvent(
SwitchStateMachine(
MediaResult{NS_ERROR_DOM_MEDIA_CDM_PROXY_NOT_SUPPORTED_ERR, aProxy});
}
#endif

View file

@ -568,6 +568,9 @@ class MediaDecoder : public DecoderDoctorLifeLogger<MediaDecoder> {
void ConnectMirrors(MediaDecoderStateMachineBase* aObject);
void DisconnectMirrors();
# ifdef MOZ_WMF_MEDIA_ENGINE
void SwitchStateMachine(const MediaResult& aError);
# endif
virtual bool CanPlayThroughImpl() = 0;

View file

@ -32,8 +32,8 @@ class MediaDecoderOwner {
// Called by the media decoder to indicate that the download is progressing.
virtual void DownloadProgressed() = 0;
// Dispatch an asynchronous event to the decoder owner
virtual void DispatchAsyncEvent(const nsAString& aName) = 0;
// Queue a task to fire an event targeted at the decoder owner
virtual void QueueEvent(const nsAString& aName) = 0;
// Triggers a recomputation of readyState.
virtual void UpdateReadyState() = 0;

View file

@ -47,8 +47,6 @@ class MediaResourceCallback
virtual void NotifyDataArrived() {}
// Notify download is ended.
// NOTE: this can be called with the media cache lock held, so don't
// block or do anything which might try to acquire a lock!
virtual void NotifyDataEnded(nsresult aStatus) {}
// Notify that the principal of MediaResource has changed.

View file

@ -28,6 +28,7 @@
#include "mozilla/SSE.h"
#include "mozilla/StaticPrefs_media.h"
#include "mozilla/SyncRunnable.h"
#include "mozilla/glean/IpcMetrics.h"
#include "mozilla/Telemetry.h"
#include "mozilla/Unused.h"
#include "nsComponentManagerUtils.h"
@ -818,8 +819,7 @@ void GMPParent::ActorDestroy(ActorDestroyReason aWhy) {
uint32_t(GMPState(mState)));
if (AbnormalShutdown == aWhy) {
Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT, "gmplugin"_ns,
1);
glean::subprocess::abnormal_abort.Get("gmplugin"_ns).Add(1);
nsString dumpID;
GetCrashID(dumpID);
if (dumpID.IsEmpty()) {

View file

@ -19,7 +19,7 @@ class MockMediaDecoderOwner final : public MediaDecoderOwner {
const PrincipalHandle& aNewPrincipalHandle),
(override));
MOCK_METHOD(void, DownloadProgressed, (), (override));
MOCK_METHOD(void, DispatchAsyncEvent, (const nsAString& aName), (override));
MOCK_METHOD(void, QueueEvent, (const nsAString& aName), (override));
MOCK_METHOD(void, UpdateReadyState, (), (override));
MOCK_METHOD(void, MaybeQueueTimeupdateEvent, (), (override));
MOCK_METHOD(bool, GetPaused, (), (override));

View file

@ -27,6 +27,7 @@
#include "mozilla/dom/MemoryReportRequest.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/glean/GleanTestsTestMetrics.h"
#include "mozilla/glean/IpcMetrics.h"
#include "mozilla/ipc/CrashReporterClient.h"
#include "mozilla/ipc/ProcessChild.h"
@ -300,7 +301,7 @@ void RDDParent::ActorDestroy(ActorDestroyReason aWhy) {
if (AbnormalShutdown == aWhy) {
NS_WARNING("Shutting down RDD process early due to a crash!");
Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT, "rdd"_ns, 1);
glean::subprocess::abnormal_abort.Get("rdd"_ns).Add(1);
ProcessChild::QuickExit();
}

View file

@ -18,7 +18,7 @@ extern mozilla::LazyLogModule gMediaElementEventsLog;
namespace mozilla::dom {
nsMediaEventRunner::nsMediaEventRunner(const nsAString& aName,
nsMediaEventRunner::nsMediaEventRunner(const char* aName,
HTMLMediaElement* aElement,
const nsAString& aEventName)
: mElement(aElement),
@ -30,11 +30,11 @@ bool nsMediaEventRunner::IsCancelled() const {
return !mElement || mElement->GetCurrentLoadID() != mLoadID;
}
nsresult nsMediaEventRunner::DispatchEvent(const nsAString& aName) {
nsresult nsMediaEventRunner::FireEvent(const nsAString& aName) {
nsresult rv = NS_OK;
if (mElement) {
ReportProfilerMarker();
rv = mElement->DispatchEvent(aName);
rv = RefPtr { mElement } -> FireEvent(aName);
}
return rv;
}
@ -112,14 +112,14 @@ NS_INTERFACE_MAP_END
NS_IMETHODIMP nsAsyncEventRunner::Run() {
// Silently cancel if our load has been cancelled or element has been CCed.
return IsCancelled() ? NS_OK : DispatchEvent(mEventName);
return IsCancelled() ? NS_OK : FireEvent(mEventName);
}
nsResolveOrRejectPendingPlayPromisesRunner::
nsResolveOrRejectPendingPlayPromisesRunner(
HTMLMediaElement* aElement, nsTArray<RefPtr<PlayPromise>>&& aPromises,
nsresult aError)
: nsMediaEventRunner(u"nsResolveOrRejectPendingPlayPromisesRunner"_ns,
: nsMediaEventRunner("nsResolveOrRejectPendingPlayPromisesRunner",
aElement),
mPromises(std::move(aPromises)),
mError(aError) {
@ -145,7 +145,7 @@ NS_IMETHODIMP nsResolveOrRejectPendingPlayPromisesRunner::Run() {
NS_IMETHODIMP nsNotifyAboutPlayingRunner::Run() {
if (!IsCancelled()) {
DispatchEvent(u"playing"_ns);
FireEvent(u"playing"_ns);
}
return nsResolveOrRejectPendingPlayPromisesRunner::Run();
}
@ -192,7 +192,7 @@ NS_IMETHODIMP nsTimeupdateRunner::Run() {
// of time then we end up spending all time handling just timeupdate events.
// The spec is vague in this situation, so we choose to update time after we
// dispatch the event in order to solve that issue.
nsresult rv = DispatchEvent(mEventName);
nsresult rv = FireEvent(mEventName);
if (NS_WARN_IF(NS_FAILED(rv))) {
LOG_EVENT(LogLevel::Debug,
("%p Failed to dispatch 'timeupdate'", mElement.get()));

View file

@ -67,33 +67,36 @@ class HTMLMediaElement;
// receive events. If we neglect to remove the self-reference then the element
// just lives longer than it needs to.
// Runnable for media element tasks.
// These tasks have special behavior if the load algorithm is triggered before
// the task is popped from the task queue, which is usually to skip running
// the task. See nsResolveOrRejectPendingPlayPromisesRunner for the exception.
class nsMediaEventRunner : public nsIRunnable, public nsINamed {
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsMediaEventRunner, nsIRunnable)
explicit nsMediaEventRunner(const nsAString& aName,
HTMLMediaElement* aElement,
explicit nsMediaEventRunner(const char* aName, HTMLMediaElement* aElement,
const nsAString& aEventName = u"unknown"_ns);
void Cancel() { mElement = nullptr; }
NS_IMETHODIMP GetName(nsACString& aName) override {
aName = NS_ConvertUTF16toUTF8(mName).get();
aName.AssignASCII(mName);
return NS_OK;
}
nsString Name() const { return mName; }
const char* Name() const { return mName; }
nsString EventName() const { return mEventName; }
protected:
virtual ~nsMediaEventRunner() = default;
bool IsCancelled() const;
nsresult DispatchEvent(const nsAString& aName);
MOZ_CAN_RUN_SCRIPT nsresult FireEvent(const nsAString& aName);
virtual void ReportProfilerMarker();
uint64_t GetElementDurationMs() const;
RefPtr<HTMLMediaElement> mElement;
nsString mName;
const char* mName;
nsString mEventName;
uint32_t mLoadID;
};
@ -104,8 +107,8 @@ class nsMediaEventRunner : public nsIRunnable, public nsINamed {
class nsAsyncEventRunner : public nsMediaEventRunner {
public:
nsAsyncEventRunner(const nsAString& aEventName, HTMLMediaElement* aElement)
: nsMediaEventRunner(u"nsAsyncEventRunner"_ns, aElement, aEventName) {}
NS_IMETHOD Run() override;
: nsMediaEventRunner("nsAsyncEventRunner", aElement, aEventName) {}
MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override;
};
/**
@ -119,6 +122,9 @@ class nsAsyncEventRunner : public nsMediaEventRunner {
* element's mPendingPlayPromisesRunners member and once the the runner is run
* (whether fulfilled or canceled), it removes itself from
* mPendingPlayPromisesRunners.
*
* If the load algorithm is triggered before the task is run then the pending
* play promises passed will be settled at commencement of the load algorithm.
*/
class nsResolveOrRejectPendingPlayPromisesRunner : public nsMediaEventRunner {
public:
@ -148,7 +154,7 @@ class nsNotifyAboutPlayingRunner
nsTArray<RefPtr<PlayPromise>>&& aPendingPlayPromises)
: nsResolveOrRejectPendingPlayPromisesRunner(
aElement, std::move(aPendingPlayPromises)) {}
NS_IMETHOD Run() override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override;
};
/**
@ -162,7 +168,7 @@ class nsSourceErrorEventRunner : public nsMediaEventRunner {
nsMediaEventRunner)
nsSourceErrorEventRunner(HTMLMediaElement* aElement, nsIContent* aSource,
const nsACString& aErrorDetails)
: nsMediaEventRunner(u"nsSourceErrorEventRunner"_ns, aElement),
: nsMediaEventRunner("nsSourceErrorEventRunner", aElement),
mSource(aSource),
mErrorDetails(NS_ConvertUTF8toUTF16(aErrorDetails)) {}
NS_IMETHOD Run() override;
@ -181,10 +187,9 @@ class nsSourceErrorEventRunner : public nsMediaEventRunner {
class nsTimeupdateRunner : public nsMediaEventRunner {
public:
nsTimeupdateRunner(HTMLMediaElement* aElement, bool aIsMandatory)
: nsMediaEventRunner(u"nsTimeupdateRunner"_ns, aElement,
u"timeupdate"_ns),
: nsMediaEventRunner("nsTimeupdateRunner", aElement, u"timeupdate"_ns),
mIsMandatory(aIsMandatory) {}
NS_IMETHOD Run() override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override;
private:
void ReportProfilerMarker() override;

View file

@ -632,4 +632,82 @@ already_AddRefed<Promise> MLS::GetGroupIdFromMessage(
return promise.forget();
}
already_AddRefed<Promise> MLS::GetGroupEpochFromMessage(
const MLSBytesOrUint8Array& aJsMessage, ErrorResult& aRv) {
MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
("MLS::GetGroupEpochFromMessage()"));
// Handle the message parameter
nsTArray<uint8_t> message =
ExtractMLSBytesOrUint8ArrayWithUnknownType(aJsMessage, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
// Check if the message is empty
if (NS_WARN_IF(message.IsEmpty())) {
aRv.ThrowTypeError("The message must not be empty");
return nullptr;
}
// Create a new Promise object for the result
RefPtr<Promise> promise = Promise::Create(mGlobalObject, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
mTransactionChild->SendRequestGetGroupEpoch(message)->Then(
GetCurrentSerialEventTarget(), __func__,
[promise, self = RefPtr{this},
message(std::move(message))](Maybe<RawBytes>&& result) {
// Check if the value is Nothing
if (result.isNothing()) {
promise->MaybeReject(NS_ERROR_FAILURE);
return;
}
// Get the context from the GlobalObject
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(self->mGlobalObject))) {
MOZ_LOG(gMlsLog, mozilla::LogLevel::Error,
("Failed to initialize JSAPI"));
promise->MaybeReject(NS_ERROR_FAILURE);
return;
}
JSContext* cx = jsapi.cx();
// Construct the Uint8Array objects based on the tag
ErrorResult error;
JS::Rooted<JSObject*> jsGroupId(
cx, Uint8Array::Create(cx, result->data(), error));
error.WouldReportJSException();
if (error.Failed()) {
promise->MaybeReject(std::move(error));
return;
}
// Construct the MLSBytes object for the groupId
RootedDictionary<MLSBytes> rvalue(cx);
rvalue.mType = MLSObjectType::Group_epoch;
rvalue.mContent.Init(jsGroupId);
// Log if in debug mode
if (MOZ_LOG_TEST(gMlsLog, LogLevel::Debug)) {
MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
("Successfully constructed MLSBytes"));
}
// Resolve the promise
promise->MaybeResolve(rvalue);
},
[promise](::mozilla::ipc::ResponseRejectReason aReason) {
MOZ_LOG(
gMlsLog, mozilla::LogLevel::Error,
("IPC call rejected with reason: %d", static_cast<int>(aReason)));
promise->MaybeRejectWithUnknownError("getGroupEpochFromMessage failed");
});
return promise.forget();
}
} // namespace mozilla::dom

View file

@ -61,6 +61,9 @@ class MLS final : public nsISupports, public nsWrapperCache {
already_AddRefed<mozilla::dom::Promise> GetGroupIdFromMessage(
const MLSBytesOrUint8Array& aJsMessage, ErrorResult& aRv);
already_AddRefed<mozilla::dom::Promise> GetGroupEpochFromMessage(
const MLSBytesOrUint8Array& aJsMessage, ErrorResult& aRv);
private:
friend class MLSGroupView;

View file

@ -952,6 +952,163 @@ already_AddRefed<Promise> MLSGroupView::Receive(
return promise.forget();
}
already_AddRefed<Promise> MLSGroupView::HasPendingProposals(ErrorResult& aRv) {
MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
("MLSGroupView::HasPendingProposals()"));
// Create a new Promise object for the result
RefPtr<Promise> promise = Promise::Create(mMLS->GetParentObject(), aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
// Receive the message
mMLS->mTransactionChild->SendRequestHasPendingProposals(mGroupId, mClientId)
->Then(
GetCurrentSerialEventTarget(), __func__,
[promise, self = RefPtr<MLSGroupView>(this)](bool&& received) {
// Get the context from the GlobalObject
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(self->mMLS->GetParentObject()))) {
MOZ_LOG(gMlsLog, mozilla::LogLevel::Error,
("Failed to initialize JSAPI"));
promise->MaybeRejectWithUnknownError(
"Failed to initialize JSAPI");
return;
}
// Resolve the promise directly with the boolean value
promise->MaybeResolve(received);
},
[promise](::mozilla::ipc::ResponseRejectReason aReason) {
MOZ_LOG(gMlsLog, mozilla::LogLevel::Error,
("IPC call rejected with reason: %d",
static_cast<int>(aReason)));
promise->MaybeRejectWithUnknownError(
"Failed to determine if there are pending proposals");
});
return promise.forget();
}
already_AddRefed<Promise> MLSGroupView::ClearPendingProposals(
ErrorResult& aRv) {
MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
("MLSGroupView::ClearPendingProposals()"));
// Create a new Promise object for the result
RefPtr<Promise> promise = Promise::Create(mMLS->GetParentObject(), aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
// Receive the message
mMLS->mTransactionChild->SendRequestClearPendingProposals(mGroupId, mClientId)
->Then(
GetCurrentSerialEventTarget(), __func__,
[promise, self = RefPtr<MLSGroupView>(this)](bool&& received) {
// Get the context from the GlobalObject
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(self->mMLS->GetParentObject()))) {
MOZ_LOG(gMlsLog, mozilla::LogLevel::Error,
("Failed to initialize JSAPI"));
promise->MaybeRejectWithUnknownError(
"Failed to initialize JSAPI");
return;
}
// Resolve the promise directly with the boolean value
promise->MaybeResolve(received);
},
[promise](::mozilla::ipc::ResponseRejectReason aReason) {
MOZ_LOG(gMlsLog, mozilla::LogLevel::Error,
("IPC call rejected with reason: %d",
static_cast<int>(aReason)));
promise->MaybeRejectWithUnknownError(
"Failed to clear pending proposals");
});
return promise.forget();
}
already_AddRefed<Promise> MLSGroupView::HasPendingCommit(ErrorResult& aRv) {
MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
("MLSGroupView::HasPendingCommit()"));
// Create a new Promise object for the result
RefPtr<Promise> promise = Promise::Create(mMLS->GetParentObject(), aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
// Receive the message
mMLS->mTransactionChild->SendRequestHasPendingCommit(mGroupId, mClientId)
->Then(
GetCurrentSerialEventTarget(), __func__,
[promise, self = RefPtr<MLSGroupView>(this)](bool&& received) {
// Get the context from the GlobalObject
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(self->mMLS->GetParentObject()))) {
MOZ_LOG(gMlsLog, mozilla::LogLevel::Error,
("Failed to initialize JSAPI"));
promise->MaybeRejectWithUnknownError(
"Failed to initialize JSAPI");
return;
}
// Resolve the promise directly with the boolean value
promise->MaybeResolve(received);
},
[promise](::mozilla::ipc::ResponseRejectReason aReason) {
MOZ_LOG(gMlsLog, mozilla::LogLevel::Error,
("IPC call rejected with reason: %d",
static_cast<int>(aReason)));
promise->MaybeRejectWithUnknownError(
"Failed to determine if there is a pending commit");
});
return promise.forget();
}
already_AddRefed<Promise> MLSGroupView::ClearPendingCommit(ErrorResult& aRv) {
MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
("MLSGroupView::ClearPendingCommit()"));
// Create a new Promise object for the result
RefPtr<Promise> promise = Promise::Create(mMLS->GetParentObject(), aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
// Receive the message
mMLS->mTransactionChild->SendRequestClearPendingCommit(mGroupId, mClientId)
->Then(
GetCurrentSerialEventTarget(), __func__,
[promise, self = RefPtr<MLSGroupView>(this)](bool&& received) {
// Get the context from the GlobalObject
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(self->mMLS->GetParentObject()))) {
MOZ_LOG(gMlsLog, mozilla::LogLevel::Error,
("Failed to initialize JSAPI"));
promise->MaybeRejectWithUnknownError(
"Failed to initialize JSAPI");
return;
}
// Resolve the promise directly with the boolean value
promise->MaybeResolve(received);
},
[promise](::mozilla::ipc::ResponseRejectReason aReason) {
MOZ_LOG(gMlsLog, mozilla::LogLevel::Error,
("IPC call rejected with reason: %d",
static_cast<int>(aReason)));
promise->MaybeRejectWithUnknownError(
"Failed to clear pending commit");
});
return promise.forget();
}
already_AddRefed<Promise> MLSGroupView::ApplyPendingCommit(ErrorResult& aRv) {
MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
("MLSGroupView::ApplyPendingCommit()"));

View file

@ -57,6 +57,15 @@ class MLSGroupView final : public nsISupports, public nsWrapperCache {
already_AddRefed<mozilla::dom::Promise> Receive(
const MLSBytesOrUint8Array& aJsMessage, ErrorResult& aRv);
already_AddRefed<mozilla::dom::Promise> HasPendingProposals(ErrorResult& aRv);
already_AddRefed<mozilla::dom::Promise> ClearPendingProposals(
ErrorResult& aRv);
already_AddRefed<mozilla::dom::Promise> HasPendingCommit(ErrorResult& aRv);
already_AddRefed<mozilla::dom::Promise> ClearPendingCommit(ErrorResult& aRv);
already_AddRefed<mozilla::dom::Promise> ApplyPendingCommit(ErrorResult& aRv);
already_AddRefed<mozilla::dom::Promise> ExportSecret(

View file

@ -443,6 +443,32 @@ mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGroupDetails(
return IPC_OK();
}
mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestSend(
const nsTArray<uint8_t>& aGroupIdentifier,
const nsTArray<uint8_t>& aIdentifier, const nsTArray<uint8_t>& aMessage,
RequestSendResolver&& aResolver) {
MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
("MLSTransactionParent::RecvRequestSend()"));
// Call to the MLS rust code
nsTArray<uint8_t> outputMessage;
nsresult rv = security::mls::mls_send(
&mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(),
aIdentifier.Elements(), aIdentifier.Length(), aMessage.Elements(),
aMessage.Length(), &outputMessage);
// Return Nothing if failed
if (NS_WARN_IF(NS_FAILED(rv))) {
aResolver(Nothing());
return IPC_OK();
}
// Return the result if success
aResolver(Some(RawBytes{std::move(outputMessage)}));
return IPC_OK();
}
mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestReceive(
const nsTArray<uint8_t>& aClientIdentifier,
const nsTArray<uint8_t>& aMessage, RequestReceiveResolver&& aResolver) {
@ -469,6 +495,106 @@ mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestReceive(
return IPC_OK();
}
mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestHasPendingProposals(
const nsTArray<uint8_t>& aGroupIdentifier,
const nsTArray<uint8_t>& aClientIdentifier,
RequestHasPendingProposalsResolver&& aResolver) {
MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
("MLSTransactionParent::RecvRequestHasPendingProposals()"));
// Call to the MLS rust code
bool received = true;
nsresult rv = security::mls::mls_has_pending_proposals(
&mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(),
aClientIdentifier.Elements(), aClientIdentifier.Length(), &received);
// Return Nothing if failed
if (NS_WARN_IF(NS_FAILED(rv))) {
aResolver(received);
return IPC_OK();
}
// Return the result if success
aResolver(received);
return IPC_OK();
}
mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestClearPendingProposals(
const nsTArray<uint8_t>& aGroupIdentifier,
const nsTArray<uint8_t>& aClientIdentifier,
RequestClearPendingProposalsResolver&& aResolver) {
MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
("MLSTransactionParent::RecvRequestCleanPendingProposals()"));
// Call to the MLS rust code
bool received = true;
nsresult rv = security::mls::mls_clear_pending_proposals(
&mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(),
aClientIdentifier.Elements(), aClientIdentifier.Length(), &received);
// Return Nothing if failed
if (NS_WARN_IF(NS_FAILED(rv))) {
aResolver(received);
return IPC_OK();
}
// Return the result if success
aResolver(received);
return IPC_OK();
}
mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestHasPendingCommit(
const nsTArray<uint8_t>& aGroupIdentifier,
const nsTArray<uint8_t>& aClientIdentifier,
RequestHasPendingCommitResolver&& aResolver) {
MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
("MLSTransactionParent::RecvRequestHasPendingCommit()"));
// Call to the MLS rust code
bool received = true;
nsresult rv = security::mls::mls_has_pending_commit(
&mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(),
aClientIdentifier.Elements(), aClientIdentifier.Length(), &received);
// Return Nothing if failed
if (NS_WARN_IF(NS_FAILED(rv))) {
aResolver(received);
return IPC_OK();
}
// Return the result if success
aResolver(received);
return IPC_OK();
}
mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestClearPendingCommit(
const nsTArray<uint8_t>& aGroupIdentifier,
const nsTArray<uint8_t>& aClientIdentifier,
RequestClearPendingCommitResolver&& aResolver) {
MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
("MLSTransactionParent::RecvRequestCleanPendingCommit()"));
// Call to the MLS rust code
bool received = true;
nsresult rv = security::mls::mls_clear_pending_commit(
&mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(),
aClientIdentifier.Elements(), aClientIdentifier.Length(), &received);
// Return Nothing if failed
if (NS_WARN_IF(NS_FAILED(rv))) {
aResolver(received);
return IPC_OK();
}
// Return the result if success
aResolver(received);
return IPC_OK();
}
mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestApplyPendingCommit(
const nsTArray<uint8_t>& aGroupIdentifier,
const nsTArray<uint8_t>& aClientIdentifier,
@ -478,7 +604,7 @@ mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestApplyPendingCommit(
// Call to the MLS rust code
GkReceived received;
nsresult rv = security::mls::mls_receive_ack(
nsresult rv = security::mls::mls_apply_pending_commit(
&mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(),
aClientIdentifier.Elements(), aClientIdentifier.Length(), &received);
@ -494,32 +620,6 @@ mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestApplyPendingCommit(
return IPC_OK();
}
mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestSend(
const nsTArray<uint8_t>& aGroupIdentifier,
const nsTArray<uint8_t>& aIdentifier, const nsTArray<uint8_t>& aMessage,
RequestSendResolver&& aResolver) {
MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
("MLSTransactionParent::RecvRequestSend()"));
// Call to the MLS rust code
nsTArray<uint8_t> outputMessage;
nsresult rv = security::mls::mls_send(
&mDatabasePath, aGroupIdentifier.Elements(), aGroupIdentifier.Length(),
aIdentifier.Elements(), aIdentifier.Length(), aMessage.Elements(),
aMessage.Length(), &outputMessage);
// Return Nothing if failed
if (NS_WARN_IF(NS_FAILED(rv))) {
aResolver(Nothing());
return IPC_OK();
}
// Return the result if success
aResolver(Some(RawBytes{std::move(outputMessage)}));
return IPC_OK();
}
mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestExportSecret(
const nsTArray<uint8_t>& aGroupIdentifier,
const nsTArray<uint8_t>& aIdentifier, const nsTArray<uint8_t>& aLabel,
@ -570,4 +670,26 @@ mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGetGroupIdentifier(
return IPC_OK();
}
mozilla::ipc::IPCResult MLSTransactionParent::RecvRequestGetGroupEpoch(
const nsTArray<uint8_t>& aMessage,
RequestGetGroupIdentifierResolver&& aResolver) {
MOZ_LOG(gMlsLog, mozilla::LogLevel::Debug,
("MLSTransactionParent::RecvRequestGetGroupEpoch()"));
nsTArray<uint8_t> groupEpoch;
nsresult rv = security::mls::mls_get_group_epoch(
aMessage.Elements(), aMessage.Length(), &groupEpoch);
// Return Nothing if failed
if (NS_WARN_IF(NS_FAILED(rv))) {
aResolver(Nothing());
return IPC_OK();
}
// Return the result if success
aResolver(Some(RawBytes{std::move(groupEpoch)}));
return IPC_OK();
}
} // namespace mozilla::dom

View file

@ -94,20 +94,40 @@ class MLSTransactionParent final : public PMLSTransactionParent {
const nsTArray<uint8_t>& aIdentifier,
RequestGroupDetailsResolver&& aResolver);
mozilla::ipc::IPCResult RecvRequestSend(
const nsTArray<uint8_t>& aGroupIdentifier,
const nsTArray<uint8_t>& aIdentifier, const nsTArray<uint8_t>& aMessage,
RequestSendResolver&& aResolver);
mozilla::ipc::IPCResult RecvRequestReceive(
const nsTArray<uint8_t>& aClientIdentifier,
const nsTArray<uint8_t>& aMessage, RequestReceiveResolver&& aResolver);
mozilla::ipc::IPCResult RecvRequestHasPendingProposals(
const nsTArray<uint8_t>& aGroupIdentifier,
const nsTArray<uint8_t>& aClientIdentifier,
RequestHasPendingProposalsResolver&& aResolver);
mozilla::ipc::IPCResult RecvRequestClearPendingProposals(
const nsTArray<uint8_t>& aGroupIdentifier,
const nsTArray<uint8_t>& aClientIdentifier,
RequestClearPendingProposalsResolver&& aResolver);
mozilla::ipc::IPCResult RecvRequestHasPendingCommit(
const nsTArray<uint8_t>& aGroupIdentifier,
const nsTArray<uint8_t>& aClientIdentifier,
RequestHasPendingCommitResolver&& aResolver);
mozilla::ipc::IPCResult RecvRequestClearPendingCommit(
const nsTArray<uint8_t>& aGroupIdentifier,
const nsTArray<uint8_t>& aClientIdentifier,
RequestClearPendingCommitResolver&& aResolver);
mozilla::ipc::IPCResult RecvRequestApplyPendingCommit(
const nsTArray<uint8_t>& aGroupIdentifier,
const nsTArray<uint8_t>& aClientIdentifier,
RequestApplyPendingCommitResolver&& aResolver);
mozilla::ipc::IPCResult RecvRequestSend(
const nsTArray<uint8_t>& aGroupIdentifier,
const nsTArray<uint8_t>& aIdentifier, const nsTArray<uint8_t>& aMessage,
RequestSendResolver&& aResolver);
mozilla::ipc::IPCResult RecvRequestExportSecret(
const nsTArray<uint8_t>& aGroupIdentifier,
const nsTArray<uint8_t>& aIdentifier, const nsTArray<uint8_t>& aLabel,
@ -118,6 +138,10 @@ class MLSTransactionParent final : public PMLSTransactionParent {
const nsTArray<uint8_t>& aMessage,
RequestGetGroupIdentifierResolver&& aResolver);
mozilla::ipc::IPCResult RecvRequestGetGroupEpoch(
const nsTArray<uint8_t>& aMessage,
RequestGetGroupEpochResolver&& aResolver);
protected:
~MLSTransactionParent() = default;
nsCString mDatabasePath;

View file

@ -34,11 +34,16 @@ parent:
async RequestGroupProposeRemove(uint8_t[] groupIdentifier, uint8_t[] identifier, uint8_t[] remIdentifier) returns (RawBytes? result);
async RequestGroupClose(uint8_t[] groupIdentifier, uint8_t[] identifier) returns (GkMlsCommitOutput? result);
async RequestGroupDetails(uint8_t[] groupIdentifier, uint8_t[] identifier) returns (GkGroupDetails? result);
async RequestReceive(uint8_t[] identifier, uint8_t[] message) returns (GkReceived result);
async RequestApplyPendingCommit(uint8_t[] groupIdentifier, uint8_t[] identifier) returns (GkReceived result);
async RequestSend(uint8_t[] groupIdentifier, uint8_t[] identifier, uint8_t[] message) returns (RawBytes? result);
async RequestReceive(uint8_t[] identifier, uint8_t[] message) returns (GkReceived result);
async RequestHasPendingProposals(uint8_t[] groupIdentifier, uint8_t[] identifier) returns (bool result);
async RequestClearPendingProposals(uint8_t[] groupIdentifier, uint8_t[] identifier) returns (bool result);
async RequestHasPendingCommit(uint8_t[] groupIdentifier, uint8_t[] identifier) returns (bool result);
async RequestClearPendingCommit(uint8_t[] groupIdentifier, uint8_t[] identifier) returns (bool result);
async RequestApplyPendingCommit(uint8_t[] groupIdentifier, uint8_t[] identifier) returns (GkReceived result);
async RequestExportSecret(uint8_t[] groupIdentifier, uint8_t[] identifier, uint8_t[] label, uint8_t[] content, uint64_t len) returns (GkExporterOutput? result);
async RequestGetGroupIdentifier(uint8_t[] message) returns (RawBytes? result);
async RequestGetGroupEpoch(uint8_t[] message) returns (RawBytes? result);
};
} // namespace dom

View file

@ -19,6 +19,10 @@ prefs = [
["test_group_remove.html"]
["test_pending.html"]
["test_scenario.html"]
["test_send_receive.html"]
["test_utils.html"]

View file

@ -0,0 +1,105 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for Messaging Layer Security</title>
<!-- SimpleTest Helpers -->
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<!-- Local Helpers -->
<script src="head_mls.js"></script>
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
async function test_pending() {
const mls = new MLS();
// Alice: Create signature keypair and credential
const alice = await mls.generateIdentity();
const alice_credential = await mls.generateCredential("alice");
// Bob: Create signature keypair and credential
const bob = await mls.generateIdentity();
const bob_credential = await mls.generateCredential("bob");
// Bob: Generate a key package
const bob_key_package = await mls.generateKeyPackage(bob, bob_credential);
// Alice: Create a group
let group_alice = await mls.groupCreate(alice, alice_credential);
// Alice: Add Bob to the group
await group_alice.add(bob_key_package);
// Check that Alice has a pending commit
let has_pending_commit = await group_alice.hasPendingCommit();
info("Does Alice have pending commit? ", has_pending_commit);
is(has_pending_commit, true);
// Discard Alice's pending commit
await group_alice.clearPendingCommit();
// Check that Alice has a pending commit
let has_pending_commit2 = await group_alice.hasPendingCommit();
info("Does Alice have pending commit? ", has_pending_commit2);
is(has_pending_commit2, false);
isnot(has_pending_commit2, null);
// Alice: Add Bob to the group
let commit_output = await group_alice.add(bob_key_package);
// Check that Alice has a pending commit
let has_pending_commit3 = await group_alice.hasPendingCommit();
info("Does Alice have pending commit? ", has_pending_commit3);
is(has_pending_commit3, true);
// Alice: process her Add commit instead of receiving the commit
await group_alice.applyPendingCommit();
// Check that Alice has a pending commit
let has_pending_commit4 = await group_alice.hasPendingCommit();
info("Does Alice have pending commit? ", has_pending_commit4);
is(has_pending_commit4, false);
isnot(has_pending_commit4, null);
// Bob: Join the group
let group_bob = await mls.groupJoin(bob, commit_output.welcome);
// Test: compare group identifier from Alice and Bob
is(byteArrayToHexString(group_alice.groupId), byteArrayToHexString(group_bob.groupId), "Alice GID == Bob GID");
// Alice & Bob: Export a secret
const context_bytes = new Uint8Array([99, 111, 110, 116, 101, 120, 116]); // "context" in ASCII
const exportAlice = await group_alice.exportSecret("label", context_bytes, 15);
const exportBob = await group_bob.exportSecret("label", context_bytes, 15);
// Test: compare exporter from Alice and Bob
is(byteArrayToHexString(exportAlice.exporter), byteArrayToHexString(exportBob.exporter), "Exporter Alice == Exporter Bob");
// Bob: send a message to the group
const message = new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 32, 33]); // "Hello World !" in ASCII
const ctx = await group_bob.send(message);
// Alice: receive a message from the group
const pt = await group_alice.receive(ctx);
info("Alice received a message from Bob: " + JSON.stringify(pt));
// Test: compare the message and the decrypted message
is(byteArrayToHexString(message), byteArrayToHexString(pt.content), "Plaintext == Decrypted Message");
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
test_pending();
</script>
</pre>
</body>
</html>

View file

@ -0,0 +1,101 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for Messaging Layer Security</title>
<!-- SimpleTest Helpers -->
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<!-- Local Helpers -->
<script src="head_mls.js"></script>
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
async function test_utils_get_group_identifier_and_epoch() {
const mls = new MLS();
// Generate Identities for Alice and Bob
let alice = await mls.generateIdentity();
let bob = await mls.generateIdentity();
// Generate Credentials for Alice and Bob
let credential_alice = await mls.generateCredential("alice");
let credential_bob = await mls.generateCredential("bob");
// Generate a KeyPackage for Bob
let kp_bob = await mls.generateKeyPackage(bob, credential_bob);
// Creation of a Group by Alice
let group_alice = await mls.groupCreate(alice, credential_alice);
// Test: compare the group identifier to the invalid value
info("Group Id:", byteArrayToHexString(group_alice.groupId));
isnot(byteArrayToHexString(group_alice.groupId), "", "Group Identifier != ''");
// Alice adds Bob to a group
let commit_output = await group_alice.add(kp_bob);
// Test: compare the commit output to the invalid value
info("Commit Output:", byteArrayToHexString(commit_output.commit));
isnot(byteArrayToHexString(commit_output.commit), "", "Commit != ''");
// Get the group details
let details = await group_alice.details();
info("Group Id:", byteArrayToHexString(details.groupId));
info("Group Epoch:", byteArrayToHexString(details.groupEpoch));
// Get the group identifier from the commit
let gid_commit = await mls.getGroupIdFromMessage(commit_output.commit);
info("Group Id from Commit Message:", byteArrayToHexString(gid_commit.content));
// Get the group identifier from the commit
let epoch_commit = await mls.getGroupEpochFromMessage(commit_output.commit);
info("Group Epoch from Commit Message:", byteArrayToHexString(epoch_commit.content));
// Note: the following is forbidden because Welcome is not an MLSMessage
// let gid_welcome = await mls.getGroupIdFromMessage(commit_output.welcome);
// info("Group Id from Welcome Message:", byteArrayToHexString(gid_welcome.content));
// Test: compare the group id of the commit to the current group id
is(byteArrayToHexString(details.groupId), byteArrayToHexString(gid_commit.content));
// Test: compare the group epoch of the commit to the current group epoch
is(byteArrayToHexString(details.groupEpoch), byteArrayToHexString(epoch_commit.content));
// Alice: process her Add commit
await group_alice.receive(commit_output.commit);
// Get the group details after processing the commit
let details2 = await group_alice.details();
info("Group Epoch 2:", byteArrayToHexString(details2.groupEpoch));
// Alice: removed Bob
let commit_output2 = await group_alice.remove(bob);
// Get the group identifier from the commit
let gid_commit2 = await mls.getGroupIdFromMessage(commit_output2.commit);
info("Group Id 2 from Commit Message 2:", byteArrayToHexString(gid_commit2.content));
// Get the group identifier from the commit2
let epoch_commit2 = await mls.getGroupEpochFromMessage(commit_output2.commit);
info("Group Epoch 2 from Commit Message 2:", byteArrayToHexString(epoch_commit2.content));
// Test: compare the group id of the commit to the current group id
is(byteArrayToHexString(details2.groupId), byteArrayToHexString(gid_commit2.content));
// Test: compare the group epoch of the commit to the current group epoch
is(byteArrayToHexString(details2.groupEpoch), byteArrayToHexString(epoch_commit2.content));
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
test_utils_get_group_identifier_and_epoch();
</script>
</pre>
</body>
</html>

View file

@ -49,7 +49,7 @@ class NotificationObserver final : public nsIObserver {
return OpenSettings(mPrincipal);
}
RefPtr<NotificationParent> actor = mActor.get();
RefPtr<NotificationParent> actor(mActor);
if (actor && actor->CanSend()) {
// The actor is alive, call it to ping the content process and/or to make
@ -201,7 +201,7 @@ nsresult NotificationParent::HandleAlertTopic(AlertTopic aTopic) {
}
nsresult NotificationParent::FireClickEvent() {
if (!mScope.IsEmpty()) {
if (!mArgs.mScope.IsEmpty()) {
return NS_OK;
}
if (SendNotifyClick()) {
@ -221,8 +221,8 @@ mozilla::ipc::IPCResult NotificationParent::RecvShow(ShowResolver&& aResolver) {
// not "granted", then queue a task to fire an event named error on this, and
// abort these steps.
NotificationPermission permission = GetNotificationPermission(
mPrincipal, mEffectiveStoragePrincipal, mIsSecureContext,
PermissionCheckPurpose::NotificationShow);
mArgs.mPrincipal, mArgs.mEffectiveStoragePrincipal,
mArgs.mIsSecureContext, PermissionCheckPurpose::NotificationShow);
if (permission != NotificationPermission::Granted) {
CopyableErrorResult rv;
rv.ThrowTypeError("Permission to show Notification denied.");
@ -259,7 +259,9 @@ nsresult NotificationParent::Show() {
// make nsIAlertsService parent process only.
nsString obsoleteCookie = u"notification:"_ns;
bool requireInteraction = mOptions.requireInteraction();
const IPCNotificationOptions& options = mArgs.mNotification.options();
bool requireInteraction = options.requireInteraction();
if (!StaticPrefs::dom_webnotifications_requireinteraction_enabled()) {
requireInteraction = false;
}
@ -269,16 +271,18 @@ nsresult NotificationParent::Show() {
if (!alert) {
return NS_ERROR_NOT_AVAILABLE;
}
MOZ_TRY(alert->Init(mOptions.tag(), mOptions.icon(), mOptions.title(),
mOptions.body(), true, obsoleteCookie,
NS_ConvertASCIItoUTF16(GetEnumString(mOptions.dir())),
mOptions.lang(), mOptions.dataSerialized(), mPrincipal,
mPrincipal->GetIsInPrivateBrowsing(), requireInteraction,
mOptions.silent(), mOptions.vibrate()));
nsCOMPtr<nsIPrincipal> principal = mArgs.mPrincipal;
MOZ_TRY(alert->Init(options.tag(), options.icon(), options.title(),
options.body(), true, obsoleteCookie,
NS_ConvertASCIItoUTF16(GetEnumString(options.dir())),
options.lang(), options.dataSerialized(), principal,
principal->GetIsInPrivateBrowsing(), requireInteraction,
options.silent(), options.vibrate()));
nsTArray<RefPtr<nsIAlertAction>> actions;
MOZ_ASSERT(mOptions.actions().Length() <= kMaxActions);
for (const auto& action : mOptions.actions()) {
MOZ_ASSERT(options.actions().Length() <= kMaxActions);
for (const auto& action : options.actions()) {
actions.AppendElement(new AlertAction(action.name(), action.title()));
}
@ -288,7 +292,7 @@ nsresult NotificationParent::Show() {
nsCOMPtr<nsIAlertsService> alertService = components::Alerts::Service();
RefPtr<NotificationObserver> observer = new NotificationObserver(
mScope, mPrincipal, IPCNotification(mId, mOptions), *this);
mArgs.mScope, principal, IPCNotification(mId, options), *this);
MOZ_TRY(alertService->ShowAlert(alert, observer));
#ifdef ANDROID
@ -315,13 +319,14 @@ void NotificationParent::Unregister() {
}
mDangling = true;
UnregisterNotification(mPrincipal, mId);
UnregisterNotification(mArgs.mPrincipal, mId);
}
nsresult NotificationParent::BindToMainThread(
nsresult NotificationParent::CreateOnMainThread(
NotificationParentArgs&& mArgs,
Endpoint<PNotificationParent>&& aParentEndpoint,
PBackgroundParent::CreateNotificationParentResolver&& aResolver) {
if (mOptions.actions().Length() > kMaxActions) {
if (mArgs.mNotification.options().actions().Length() > kMaxActions) {
return NS_ERROR_INVALID_ARG;
}
@ -329,9 +334,11 @@ nsresult NotificationParent::BindToMainThread(
NS_DispatchToMainThread(NS_NewRunnableFunction(
"NotificationParent::BindToMainThread",
[self = RefPtr(this), endpoint = std::move(aParentEndpoint),
[args = std::move(mArgs), endpoint = std::move(aParentEndpoint),
resolver = std::move(aResolver), thread]() mutable {
bool result = endpoint.Bind(self);
RefPtr<NotificationParent> actor =
new NotificationParent(std::move(args));
bool result = endpoint.Bind(actor);
thread->Dispatch(NS_NewRunnableFunction(
"NotificationParent::BindToMainThreadResult",
[result, resolver = std::move(resolver)]() { resolver(result); }));

View file

@ -23,35 +23,34 @@ enum class AlertTopic : uint8_t {
Finished,
};
struct NotificationParentArgs {
NotNull<nsCOMPtr<nsIPrincipal>> mPrincipal;
NotNull<nsCOMPtr<nsIPrincipal>> mEffectiveStoragePrincipal;
bool mIsSecureContext;
nsString mScope;
IPCNotification mNotification;
};
class NotificationParent final : public PNotificationParent,
public nsISupports,
public SupportsWeakPtr {
using IPCResult = mozilla::ipc::IPCResult;
public:
// Threadsafe to pass the class from PBackground to main thread
NS_DECL_THREADSAFE_ISUPPORTS
NotificationParent(NotNull<nsIPrincipal*> aPrincipal,
NotNull<nsIPrincipal*> aEffectiveStoragePrincipal,
bool aIsSecureContext, const nsAString& aScope,
const IPCNotification& aNotification)
: mPrincipal(aPrincipal),
mEffectiveStoragePrincipal(aEffectiveStoragePrincipal),
mIsSecureContext(aIsSecureContext),
mId(aNotification.id()),
mScope(aScope),
mOptions(aNotification.options()) {};
NS_DECL_ISUPPORTS
nsresult HandleAlertTopic(AlertTopic aTopic);
IPCResult RecvShow(ShowResolver&& aResolver);
IPCResult RecvClose();
nsresult BindToMainThread(
static nsresult CreateOnMainThread(
NotificationParentArgs&& mArgs,
Endpoint<PNotificationParent>&& aParentEndpoint,
PBackgroundParent::CreateNotificationParentResolver&& aResolver);
private:
explicit NotificationParent(NotificationParentArgs&& aArgs)
: mId(aArgs.mNotification.id()), mArgs(std::move(aArgs)) {};
~NotificationParent() = default;
nsresult Show();
@ -61,17 +60,10 @@ class NotificationParent final : public PNotificationParent,
Maybe<NotificationParent::ShowResolver> mResolver;
NotNull<nsCOMPtr<nsIPrincipal>> mPrincipal;
NotNull<nsCOMPtr<nsIPrincipal>> mEffectiveStoragePrincipal;
bool mIsSecureContext;
// The ID generated by nsIAlertNotification during Show() function. It may
// stay empty if the function fails.
nsString mId;
nsString mScope;
const IPCNotificationOptions mOptions;
nsString mAlertName;
const NotificationParentArgs mArgs;
// Whether it's now a dangling actor without corresponding OS notification,
// either because it's closed or denied permission. We don't have to call

View file

@ -8,7 +8,6 @@
#include "mozilla/dom/PrototypeDocumentContentSink.h"
#include "nsIParser.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/URL.h"
#include "nsIContent.h"
#include "nsIURI.h"
#include "nsNetUtil.h"
@ -666,7 +665,7 @@ nsresult PrototypeDocumentContentSink::DoneWalking() {
StartLayout();
if (IsChromeURI(mDocumentURI) &&
if (mDocumentURI->SchemeIs("chrome") &&
nsXULPrototypeCache::GetInstance()->IsEnabled()) {
bool isCachedOnDisk;
nsXULPrototypeCache::GetInstance()->HasPrototype(mDocumentURI,
@ -733,7 +732,7 @@ nsresult PrototypeDocumentContentSink::LoadScript(
// Load a transcluded script
nsresult rv;
bool isChromeDoc = IsChromeURI(mDocumentURI);
bool isChromeDoc = mDocumentURI->SchemeIs("chrome");
if (isChromeDoc && aScriptProto->HasStencil()) {
rv = ExecuteScript(aScriptProto);
@ -938,7 +937,8 @@ PrototypeDocumentContentSink::OnScriptCompileComplete(JS::Stencil* aStencil,
// the true crime story.)
bool useXULCache = nsXULPrototypeCache::GetInstance()->IsEnabled();
if (useXULCache && IsChromeURI(mDocumentURI) && scriptProto->HasStencil()) {
if (useXULCache && mDocumentURI->SchemeIs("chrome") &&
scriptProto->HasStencil()) {
nsXULPrototypeCache::GetInstance()->PutStencil(scriptProto->mSrcURI,
scriptProto->GetStencil());
}

View file

@ -2435,7 +2435,10 @@ nsresult ScriptLoader::ProcessRequest(ScriptLoadRequest* aRequest) {
if (runScript) {
nsContentUtils::DispatchTrustedEvent(
scriptElem->OwnerDoc(), scriptElem, u"beforescriptexecute"_ns,
CanBubble::eYes, Cancelable::eYes, &runScript);
CanBubble::eYes, Cancelable::eYes, &runScript,
StaticPrefs::dom_events_script_execute_enabled()
? SystemGroupOnly::eNo
: SystemGroupOnly::eYes);
}
// Inner window could have gone away after firing beforescriptexecute
@ -2454,9 +2457,12 @@ nsresult ScriptLoader::ProcessRequest(ScriptLoadRequest* aRequest) {
doc->DecrementIgnoreDestructiveWritesCounter();
}
nsContentUtils::DispatchTrustedEvent(scriptElem->OwnerDoc(), scriptElem,
u"afterscriptexecute"_ns,
CanBubble::eYes, Cancelable::eNo);
nsContentUtils::DispatchTrustedEvent(
scriptElem->OwnerDoc(), scriptElem, u"afterscriptexecute"_ns,
CanBubble::eYes, Cancelable::eNo, nullptr,
StaticPrefs::dom_events_script_execute_enabled()
? SystemGroupOnly::eNo
: SystemGroupOnly::eYes);
}
FireScriptEvaluated(rv, aRequest);

View file

@ -233,6 +233,13 @@ nsIGlobalObject* GetCurrentGlobal() {
return xpc::NativeGlobal(global);
}
WebTaskSchedulingState* GetWebTaskSchedulingState() {
if (const nsIGlobalObject* global = GetEntryGlobal()) {
return global->GetWebTaskSchedulingState();
}
return nullptr;
}
nsIPrincipal* GetWebIDLCallerPrincipal() {
MOZ_ASSERT(NS_IsMainThread());
ScriptSettingsStackEntry* entry = ScriptSettingsStack::EntryPoint();

View file

@ -35,6 +35,7 @@ namespace mozilla {
namespace dom {
class Document;
class WebTaskSchedulingState;
/*
* Per thread setup/teardown routines. Init and Destroy should be invoked
@ -95,6 +96,8 @@ nsIGlobalObject* GetIncumbentGlobal();
// Returns the global associated with the current compartment. This may be null.
nsIGlobalObject* GetCurrentGlobal();
WebTaskSchedulingState* GetWebTaskSchedulingState();
// JS-implemented WebIDL presents an interesting situation with respect to the
// subject principal. A regular C++-implemented API can simply examine the
// compartment of the most-recently-executed script, and use that to infer the

View file

@ -1005,10 +1005,9 @@ void StripURIForReporting(nsIURI* aSelfURI, nsIURI* aURI,
// If the origin of aURI is a globally unique identifier (for example,
// aURI has a scheme of data, blob, or filesystem), then
// return the ASCII serialization of uris scheme.
bool isHttpOrWs = (aURI->SchemeIs("http") || aURI->SchemeIs("https") ||
aURI->SchemeIs("ws") || aURI->SchemeIs("wss"));
bool isWsOrWss = aURI->SchemeIs("ws") || aURI->SchemeIs("wss");
if (!isHttpOrWs) {
if (!net::SchemeIsHttpOrHttps(aURI) && !isWsOrWss) {
// not strictly spec compliant, but what we really care about is
// http/https. If it's not http/https, then treat aURI
// as if it's a globally unique identifier and just return the scheme.
@ -1337,10 +1336,7 @@ nsresult nsCSPContext::SendReportsToURIs(
}
// log a warning to console if scheme is not http or https
bool isHttpScheme =
reportURI->SchemeIs("http") || reportURI->SchemeIs("https");
if (!isHttpScheme) {
if (!net::SchemeIsHttpOrHttps(reportURI)) {
AutoTArray<nsString, 1> params = {reportURIs[r]};
logToConsole("reportURInotHttpsOrHttp2", params,
NS_ConvertUTF16toUTF8(aViolationEventInit.mSourceFile),

View file

@ -98,8 +98,7 @@ bool nsContentSecurityManager::AllowTopLevelNavigationToDataURI(
nsCOMPtr<nsIURI> uri;
nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, true);
bool isDataURI = uri->SchemeIs("data");
if (!isDataURI) {
if (!uri->SchemeIs("data")) {
return true;
}
@ -175,11 +174,7 @@ bool nsContentSecurityManager::AllowInsecureRedirectToDataURI(
}
nsCOMPtr<nsIURI> newURI;
nsresult rv = NS_GetFinalChannelURI(aNewChannel, getter_AddRefs(newURI));
if (NS_FAILED(rv) || !newURI) {
return true;
}
bool isDataURI = newURI->SchemeIs("data");
if (!isDataURI) {
if (NS_FAILED(rv) || !newURI || !newURI->SchemeIs("data")) {
return true;
}
@ -1007,15 +1002,15 @@ nsresult nsContentSecurityManager::CheckAllowLoadInSystemPrivilegedContext(
if (contentPolicyType == ExtContentPolicy::TYPE_SUBDOCUMENT) {
if (StaticPrefs::security_disallow_privileged_https_subdocuments_loads() &&
(innerURI->SchemeIs("http") || innerURI->SchemeIs("https"))) {
net::SchemeIsHttpOrHttps(innerURI)) {
MOZ_ASSERT(
false,
"Disallowing SystemPrincipal load of subdocuments on HTTP(S).");
aChannel->Cancel(NS_ERROR_CONTENT_BLOCKED);
return NS_ERROR_CONTENT_BLOCKED;
}
if ((StaticPrefs::security_disallow_privileged_data_subdocuments_loads()) &&
(innerURI->SchemeIs("data"))) {
if (StaticPrefs::security_disallow_privileged_data_subdocuments_loads() &&
innerURI->SchemeIs("data")) {
MOZ_ASSERT(
false,
"Disallowing SystemPrincipal load of subdocuments on data URL.");
@ -1024,8 +1019,8 @@ nsresult nsContentSecurityManager::CheckAllowLoadInSystemPrivilegedContext(
}
}
if (contentPolicyType == ExtContentPolicy::TYPE_SCRIPT) {
if ((StaticPrefs::security_disallow_privileged_https_script_loads()) &&
(innerURI->SchemeIs("http") || innerURI->SchemeIs("https"))) {
if (StaticPrefs::security_disallow_privileged_https_script_loads() &&
net::SchemeIsHttpOrHttps(innerURI)) {
MOZ_ASSERT(false,
"Disallowing SystemPrincipal load of scripts on HTTP(S).");
aChannel->Cancel(NS_ERROR_CONTENT_BLOCKED);
@ -1034,7 +1029,7 @@ nsresult nsContentSecurityManager::CheckAllowLoadInSystemPrivilegedContext(
}
if (contentPolicyType == ExtContentPolicy::TYPE_STYLESHEET) {
if (StaticPrefs::security_disallow_privileged_https_stylesheet_loads() &&
(innerURI->SchemeIs("http") || innerURI->SchemeIs("https"))) {
net::SchemeIsHttpOrHttps(innerURI)) {
MOZ_ASSERT(false,
"Disallowing SystemPrincipal load of stylesheets on HTTP(S).");
aChannel->Cancel(NS_ERROR_CONTENT_BLOCKED);
@ -1091,8 +1086,7 @@ nsresult nsContentSecurityManager::CheckAllowLoadInPrivilegedAboutContext(
&isLocal);
// We allow URLs that are URI_IS_LOCAL (but that includes `data`
// and `blob` which are also undesirable.
if ((isLocal) && (!innerURI->SchemeIs("data")) &&
(!innerURI->SchemeIs("blob"))) {
if (isLocal && !innerURI->SchemeIs("data") && !innerURI->SchemeIs("blob")) {
return NS_OK;
}
MOZ_ASSERT(
@ -1759,10 +1753,8 @@ nsresult nsContentSecurityManager::CheckForIncoherentResultPrincipal(
if (nsScriptSecurityManager::IsHttpOrHttpsAndCrossOrigin(
resultSiteOriginURI, channelSiteOriginURI) ||
(!net::SchemeIsHTTP(resultSiteOriginURI) &&
!net::SchemeIsHTTPS(resultSiteOriginURI) &&
(net::SchemeIsHTTP(channelSiteOriginURI) ||
net::SchemeIsHTTPS(channelSiteOriginURI)))) {
(!net::SchemeIsHttpOrHttps(resultSiteOriginURI) &&
net::SchemeIsHttpOrHttps(channelSiteOriginURI))) {
return NS_ERROR_CONTENT_BLOCKED;
}

View file

@ -1487,15 +1487,16 @@ class DisallowingVisitor : public nsCSPSrcVisitor {
nsCString mURL;
};
class AllowChromeResourceSrcVisitor : public DisallowingVisitor {
// Only allows loads from chrome:, moz-src: and resource: URLs:
class AllowBuiltinSrcVisitor : public DisallowingVisitor {
public:
AllowChromeResourceSrcVisitor(CSPDirective aDirective, nsACString& aURL)
AllowBuiltinSrcVisitor(CSPDirective aDirective, nsACString& aURL)
: DisallowingVisitor(aDirective, aURL) {}
bool visitSchemeSrc(const nsCSPSchemeSrc& src) override {
nsAutoString scheme;
src.getScheme(scheme);
if (scheme == u"chrome"_ns || scheme == u"resource"_ns) {
if (scheme == u"chrome"_ns || scheme == u"moz-src" || scheme == u"resource"_ns) {
return true;
}
@ -1527,10 +1528,10 @@ class AllowChromeResourceSrcVisitor : public DisallowingVisitor {
}
};
class StyleSrcVisitor : public AllowChromeResourceSrcVisitor {
class StyleSrcVisitor : public AllowBuiltinSrcVisitor {
public:
StyleSrcVisitor(CSPDirective aDirective, nsACString& aURL)
: AllowChromeResourceSrcVisitor(aDirective, aURL) {
: AllowBuiltinSrcVisitor(aDirective, aURL) {
MOZ_ASSERT(aDirective == CSPDirective::STYLE_SRC_DIRECTIVE);
}
@ -1544,7 +1545,7 @@ class StyleSrcVisitor : public AllowChromeResourceSrcVisitor {
}
}
return AllowChromeResourceSrcVisitor::visitSchemeSrc(src);
return AllowBuiltinSrcVisitor::visitSchemeSrc(src);
}
bool visitKeywordSrc(const nsCSPKeywordSrc& src) override {
@ -1554,14 +1555,14 @@ class StyleSrcVisitor : public AllowChromeResourceSrcVisitor {
}
}
return AllowChromeResourceSrcVisitor::visitKeywordSrc(src);
return AllowBuiltinSrcVisitor::visitKeywordSrc(src);
}
};
class ImgSrcVisitor : public AllowChromeResourceSrcVisitor {
class ImgSrcVisitor : public AllowBuiltinSrcVisitor {
public:
ImgSrcVisitor(CSPDirective aDirective, nsACString& aURL)
: AllowChromeResourceSrcVisitor(aDirective, aURL) {
: AllowBuiltinSrcVisitor(aDirective, aURL) {
MOZ_ASSERT(aDirective == CSPDirective::IMG_SRC_DIRECTIVE);
}
@ -1599,7 +1600,7 @@ class ImgSrcVisitor : public AllowChromeResourceSrcVisitor {
}
}
return AllowChromeResourceSrcVisitor::visitSchemeSrc(src);
return AllowBuiltinSrcVisitor::visitSchemeSrc(src);
}
bool visitHostSrc(const nsCSPHostSrc& src) override {
@ -1608,10 +1609,10 @@ class ImgSrcVisitor : public AllowChromeResourceSrcVisitor {
}
};
class MediaSrcVisitor : public AllowChromeResourceSrcVisitor {
class MediaSrcVisitor : public AllowBuiltinSrcVisitor {
public:
MediaSrcVisitor(CSPDirective aDirective, nsACString& aURL)
: AllowChromeResourceSrcVisitor(aDirective, aURL) {
: AllowBuiltinSrcVisitor(aDirective, aURL) {
MOZ_ASSERT(aDirective == CSPDirective::MEDIA_SRC_DIRECTIVE);
}
@ -1626,7 +1627,7 @@ class MediaSrcVisitor : public AllowChromeResourceSrcVisitor {
}
}
return AllowChromeResourceSrcVisitor::visitSchemeSrc(src);
return AllowBuiltinSrcVisitor::visitSchemeSrc(src);
}
bool visitHostSrc(const nsCSPHostSrc& src) override {
@ -1635,10 +1636,10 @@ class MediaSrcVisitor : public AllowChromeResourceSrcVisitor {
}
};
class ConnectSrcVisitor : public AllowChromeResourceSrcVisitor {
class ConnectSrcVisitor : public AllowBuiltinSrcVisitor {
public:
ConnectSrcVisitor(CSPDirective aDirective, nsACString& aURL)
: AllowChromeResourceSrcVisitor(aDirective, aURL) {
: AllowBuiltinSrcVisitor(aDirective, aURL) {
MOZ_ASSERT(aDirective == CSPDirective::CONNECT_SRC_DIRECTIVE);
}
@ -1658,14 +1659,14 @@ class ConnectSrcVisitor : public AllowChromeResourceSrcVisitor {
}
}
return AllowChromeResourceSrcVisitor::visitSchemeSrc(src);
return AllowBuiltinSrcVisitor::visitSchemeSrc(src);
}
};
class AddonSrcVisitor : public AllowChromeResourceSrcVisitor {
class AddonSrcVisitor : public AllowBuiltinSrcVisitor {
public:
AddonSrcVisitor(CSPDirective aDirective, nsACString& aURL)
: AllowChromeResourceSrcVisitor(aDirective, aURL) {
: AllowBuiltinSrcVisitor(aDirective, aURL) {
MOZ_ASSERT(aDirective == CSPDirective::DEFAULT_SRC_DIRECTIVE ||
aDirective == CSPDirective::SCRIPT_SRC_DIRECTIVE);
}
@ -1676,14 +1677,14 @@ class AddonSrcVisitor : public AllowChromeResourceSrcVisitor {
if (str == u"'self'"_ns) {
return true;
}
return AllowChromeResourceSrcVisitor::visitHostSrc(src);
return AllowBuiltinSrcVisitor::visitHostSrc(src);
}
bool visitHashSrc(const nsCSPHashSrc& src) override {
if (mDirective == CSPDirective::SCRIPT_SRC_DIRECTIVE) {
return true;
}
return AllowChromeResourceSrcVisitor::visitHashSrc(src);
return AllowBuiltinSrcVisitor::visitHashSrc(src);
}
};
@ -1824,7 +1825,7 @@ void nsContentSecurityUtils::AssertAboutPageHasCSP(Document* aDocument) {
const nsCSPPolicy* policy = csp->GetPolicy(0);
{
AllowChromeResourceSrcVisitor visitor(CSPDirective::DEFAULT_SRC_DIRECTIVE,
AllowBuiltinSrcVisitor visitor(CSPDirective::DEFAULT_SRC_DIRECTIVE,
spec);
if (!visitor.visit(policy)) {
MOZ_ASSERT(false, "about: page must contain a secure default-src");
@ -1840,7 +1841,7 @@ void nsContentSecurityUtils::AssertAboutPageHasCSP(Document* aDocument) {
}
}
CHECK_DIR(SCRIPT_SRC_DIRECTIVE, AllowChromeResourceSrcVisitor);
CHECK_DIR(SCRIPT_SRC_DIRECTIVE, AllowBuiltinSrcVisitor);
CHECK_DIR(STYLE_SRC_DIRECTIVE, StyleSrcVisitor);
CHECK_DIR(IMG_SRC_DIRECTIVE, ImgSrcVisitor);
CHECK_DIR(MEDIA_SRC_DIRECTIVE, MediaSrcVisitor);
@ -1902,7 +1903,7 @@ void nsContentSecurityUtils::AssertChromePageHasCSP(Document* aDocument) {
const nsCSPPolicy* policy =
static_cast<nsCSPContext*>(csp.get())->GetPolicy(0);
{
AllowChromeResourceSrcVisitor visitor(CSPDirective::DEFAULT_SRC_DIRECTIVE,
AllowBuiltinSrcVisitor visitor(CSPDirective::DEFAULT_SRC_DIRECTIVE,
spec);
if (!visitor.visit(policy)) {
MOZ_CRASH_UNSAFE_PRINTF(
@ -1910,7 +1911,7 @@ void nsContentSecurityUtils::AssertChromePageHasCSP(Document* aDocument) {
}
}
CHECK_DIR(SCRIPT_SRC_DIRECTIVE, AllowChromeResourceSrcVisitor);
CHECK_DIR(SCRIPT_SRC_DIRECTIVE, AllowBuiltinSrcVisitor);
// If the policy being checked does not have an explicit |script-src-attr|
// directive, nsCSPPolicy::visitDirectiveSrcs will fallback to using the
// |script-src| directive, but not default-src.
@ -1918,7 +1919,7 @@ void nsContentSecurityUtils::AssertChromePageHasCSP(Document* aDocument) {
// fallback will usually contain at least a chrome: source.
// This is not a problem from a security perspective, because inline scripts
// are not loaded from an URL and thus still disallowed.
CHECK_DIR(SCRIPT_SRC_ATTR_DIRECTIVE, AllowChromeResourceSrcVisitor);
CHECK_DIR(SCRIPT_SRC_ATTR_DIRECTIVE, AllowBuiltinSrcVisitor);
CHECK_DIR(STYLE_SRC_DIRECTIVE, StyleSrcVisitor);
CHECK_DIR(IMG_SRC_DIRECTIVE, ImgSrcVisitor);
CHECK_DIR(MEDIA_SRC_DIRECTIVE, MediaSrcVisitor);
@ -1951,7 +1952,6 @@ void nsContentSecurityUtils::AssertChromePageHasCSP(Document* aDocument) {
"chrome://browser/content/safeMode.xhtml"_ns,
"chrome://browser/content/shopping/review-checker.xhtml"_ns,
"chrome://browser/content/webext-panels.xhtml"_ns,
"chrome://browser/content/webrtcIndicator.xhtml"_ns,
"chrome://extensions/content/dummy.xhtml"_ns,
"chrome://geckoview/content/geckoview.xhtml"_ns,
"chrome://global/content/alerts/alert.xhtml"_ns,

View file

@ -927,12 +927,12 @@ bool nsHTTPSOnlyUtils::IsHttpDowngrade(nsIURI* aFromURI, nsIURI* aToURI) {
}
// 2. If the target URI is not http, then it's not a http downgrade
if (!mozilla::net::SchemeIsHTTP(aToURI)) {
if (!aToURI->SchemeIs("http")) {
return false;
}
// 3. If the origin URI isn't https, then it's not a http downgrade either.
if (!mozilla::net::SchemeIsHTTPS(aFromURI)) {
if (!aFromURI->SchemeIs("https")) {
return false;
}

View file

@ -391,18 +391,20 @@ static CanonicalName CanonicalizeElement(const SanitizerElement& aElement) {
const auto& elem = GetAsSanitizerElementNamespace(aElement);
MOZ_ASSERT(!elem.mName.IsVoid());
// Step 4. Return «[
RefPtr<nsAtom> namespaceAtom;
// Step 4. Let namespace be name["namespace"] if it exists, otherwise defaultNamespace.
// Note: "namespace" always exists due to the WebIDL default value.
// Step 5. If namespace is the empty string, then set it to null.
if (!elem.mNamespace.IsEmpty()) {
namespaceAtom = NS_AtomizeMainThread(elem.mNamespace);
}
// Step 6. Return «[
// "name" → name["name"],
// "namespace" → ( name["namespace"] if it exists, otherwise defaultNamespace
// "namespace" → namespace
// )
// ]».
RefPtr<nsAtom> nameAtom = NS_AtomizeMainThread(elem.mName);
RefPtr<nsAtom> namespaceAtom;
if (!elem.mNamespace.IsVoid()) {
namespaceAtom = NS_AtomizeMainThread(elem.mNamespace);
} else {
namespaceAtom = nsGkAtoms::nsuri_xhtml;
}
return CanonicalName(nameAtom, namespaceAtom);
}
@ -427,16 +429,19 @@ static CanonicalName CanonicalizeAttribute(
const auto& attr = aAttribute.GetAsSanitizerAttributeNamespace();
MOZ_ASSERT(!attr.mName.IsVoid());
// Step 4. Return «[
RefPtr<nsAtom> namespaceAtom;
// Step 4. Let namespace be name["namespace"] if it exists, otherwise defaultNamespace.
// Step 5. If namespace is the empty string, then set it to null.
if (!attr.mNamespace.IsEmpty()) {
namespaceAtom = NS_AtomizeMainThread(attr.mNamespace);
}
// Step 6. Return «[
// "name" → name["name"],
// "namespace" → ( name["namespace"] if it exists, otherwise defaultNamespace
// "namespace" → namespace,
// )
// ]».
RefPtr<nsAtom> nameAtom = NS_AtomizeMainThread(attr.mName);
RefPtr<nsAtom> namespaceAtom = nullptr;
if (!attr.mNamespace.IsVoid()) {
namespaceAtom = NS_AtomizeMainThread(attr.mNamespace);
}
return CanonicalName(nameAtom, namespaceAtom);
}
@ -708,35 +713,33 @@ static bool IsUnsafeElement(nsAtom* aLocalName, int32_t aNamespaceID) {
// https://wicg.github.io/sanitizer-api/#sanitize-core
template <bool IsDefaultConfig>
void Sanitizer::SanitizeChildren(nsINode* aNode, bool aSafe) {
// Step 1. Let current be node.
// Step 2. For each child in currents children:
// Step 1. For each child in currents children:
nsCOMPtr<nsIContent> next = nullptr;
for (nsCOMPtr<nsIContent> child = aNode->GetFirstChild(); child;
child = next) {
next = child->GetNextSibling();
// Step 2.1. Assert: child implements Text, Comment, or Element.
// Step 1.1. Assert: child implements Text, Comment, or Element.
// TODO
// Step 2.2. If child implements Text, then continue.
// Step 1.2. If child implements Text, then continue.
if (child->IsText()) {
continue;
}
// Step 2.3. If child implements Comment:
// Step 1.3. If child implements Comment:
if (child->IsComment()) {
// Step 2.3.1 If configuration["comments"] is not true, then remove child.
// Step 1.3.1 If configuration["comments"] is not true, then remove child.
if (!mComments) {
child->RemoveFromParent();
}
continue;
}
// Step 2.4. Otherwise:
// Step 1.4. Otherwise:
MOZ_ASSERT(child->IsElement());
// Step 2.4.1. Let elementName be a SanitizerElementNamespace with childs
// Step 1.4.1. Let elementName be a SanitizerElementNamespace with childs
// local name and namespace.
nsAtom* nameAtom = child->NodeInfo()->NameAtom();
int32_t namespaceID = child->NodeInfo()->NamespaceID();
@ -749,6 +752,10 @@ void Sanitizer::SanitizeChildren(nsINode* aNode, bool aSafe) {
// Optimization: Remove unsafe elements before doing anything else.
// https://wicg.github.io/sanitizer-api/#built-in-safe-baseline-configuration
//
// We have to do this _before_ handling the "replaceWithChildrenElements"
// list, because by adding the unsafe elements to the "removeElements" list
// they would be implicitly deleted from the former.
//
// The default config's "elements" allow list does not contain any unsafe
// elements so we can skip this.
if constexpr (!IsDefaultConfig) {
@ -759,15 +766,44 @@ void Sanitizer::SanitizeChildren(nsINode* aNode, bool aSafe) {
}
}
// Step 2.4.2. If configuration["removeElements"] contains elementName, or
// Step 1.4.2. If configuration["replaceWithChildrenElements"] contains
// elementName:
if constexpr (!IsDefaultConfig) {
if (mReplaceWithChildrenElements.Contains(*elementName)) {
// Note: This follows nsTreeSanitizer by first inserting the
// child's children in place of the current child and then
// continueing the sanitization from the first inserted grandchild.
nsCOMPtr<nsIContent> parent = child->GetParent();
nsCOMPtr<nsIContent> firstChild = child->GetFirstChild();
nsCOMPtr<nsIContent> newChild = firstChild;
for (; newChild; newChild = child->GetFirstChild()) {
ErrorResult rv;
parent->InsertBefore(*newChild, child, rv);
if (rv.Failed()) {
// TODO: Abort?
break;
}
}
child->RemoveFromParent();
if (firstChild) {
next = firstChild;
}
continue;
}
}
// Step 1.4.3. If configuration["removeElements"] contains elementName, or
// if configuration["elements"] is not empty and does not contain
// elementName, then remove child.
// elementName:
[[maybe_unused]] StaticAtomSet* elementAttributes = nullptr;
if constexpr (!IsDefaultConfig) {
if (mRemoveElements.Contains(*elementName) ||
(!mElements.IsEmpty() && !mElements.Contains(*elementName))) {
// TODO: Do the more complex remove node stuff from nsTreeSanitizer.
// Step 1.4.3.1. Remove child.
child->RemoveFromParent();
// Step 1.4.3.2. Continue.
continue;
}
} else {
@ -789,54 +825,30 @@ void Sanitizer::SanitizeChildren(nsINode* aNode, bool aSafe) {
}
}
if (!found) {
// Step 1.4.3.1. Remove child.
child->RemoveFromParent();
// Step 1.4.3.2. Continue.
continue;
}
MOZ_ASSERT(!IsUnsafeElement(nameAtom, namespaceID));
}
// Step 2.4.3. If configuration["replaceWithChildrenElements"] contains
// elementName:
if constexpr (!IsDefaultConfig) {
if (mReplaceWithChildrenElements.Contains(*elementName)) {
// Note: This follows nsTreeSanitizer by first inserting the
// child's children in place of the current child and then
// continueing the sanitization from the first inserted grandchild.
nsCOMPtr<nsIContent> parent = child->GetParent();
nsCOMPtr<nsIContent> firstChild = child->GetFirstChild();
nsCOMPtr<nsIContent> newChild = firstChild;
for (; newChild; newChild = child->GetFirstChild()) {
ErrorResult rv;
parent->InsertBefore(*newChild, child, rv);
if (rv.Failed()) {
break;
}
}
child->RemoveFromParent();
if (firstChild) {
next = firstChild;
}
continue;
}
}
// Step 2.4.4. If elementName equals «[ "name" → "template", "namespace" →
// Step 1.4.4. If elementName equals «[ "name" → "template", "namespace" →
// HTML namespace ]»
if (auto* templateEl = HTMLTemplateElement::FromNode(child)) {
// Step 2.4.4.1. Then call sanitize core on childs template contents with
// Step 1.4.4.1. Then call sanitize core on childs template contents with
// configuration and handleJavascriptNavigationUrls.
RefPtr<DocumentFragment> frag = templateEl->Content();
SanitizeChildren<IsDefaultConfig>(frag, aSafe);
}
// Step 2.4.5. If child is a shadow host, then call sanitize core on childs
// Step 1.4.5. If child is a shadow host, then call sanitize core on childs
// shadow root with configuration and handleJavascriptNavigationUrls.
if (RefPtr<ShadowRoot> shadow = child->GetShadowRoot()) {
SanitizeChildren<IsDefaultConfig>(shadow, aSafe);
}
// Step 2.4.6.
// Step 1.4.6.
if constexpr (!IsDefaultConfig) {
SanitizeAttributes(child->AsElement(), *elementName, aSafe);
} else {
@ -844,7 +856,8 @@ void Sanitizer::SanitizeChildren(nsINode* aNode, bool aSafe) {
aSafe);
}
// XXX: Recursion missing from the spec ?!?
// Step 1.4.7. Call sanitize core on child with configuration and
// handleJavascriptNavigationUrls.
// TODO: Optimization: Remove recusion similar to nsTreeSanitizer
SanitizeChildren<IsDefaultConfig>(child, aSafe);
}

View file

@ -26,7 +26,7 @@ CanonicalElementWithAttributes::ToSanitizerElementNamespaceWithAttributes()
if (mNamespace) {
mNamespace->ToString(result.mNamespace);
} else {
MOZ_ASSERT(false, "An element namespace should never be null");
result.mNamespace.SetIsVoid(true);
}
if (mAttributes) {
result.mAttributes.Construct(ToSanitizerAttributes(*mAttributes));
@ -44,7 +44,7 @@ SanitizerElementNamespace CanonicalName::ToSanitizerElementNamespace() const {
if (mNamespace) {
mNamespace->ToString(result.mNamespace);
} else {
MOZ_ASSERT(false, "An element namespace should never be null");
result.mNamespace.SetIsVoid(true);
}
return result;
}

View file

@ -236,7 +236,7 @@ void ServiceWorkerScopeAndScriptAreValid(const ClientInfo& aClientInfo,
}
auto hasHTTPScheme = [](nsIURI* aURI) -> bool {
return aURI->SchemeIs("http") || aURI->SchemeIs("https");
return net::SchemeIsHttpOrHttps(aURI);
};
auto hasMozExtScheme = [](nsIURI* aURI) -> bool {
return aURI->SchemeIs("moz-extension");

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