Update On Tue Apr 1 20:55:44 CEST 2025
This commit is contained in:
parent
7fd5129ae4
commit
c2daad41dd
553 changed files with 18696 additions and 10865 deletions
|
@ -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 \
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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" />
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -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"]
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 can’t 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}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -193,7 +193,6 @@
|
|||
// Check for middle-click or modified clicks on the search bar
|
||||
BrowserSearchTelemetry.recordSearchSuggestionSelectionMethod(
|
||||
aEvent,
|
||||
"searchbar",
|
||||
this.selectedIndex
|
||||
);
|
||||
|
||||
|
|
|
@ -332,7 +332,6 @@
|
|||
|
||||
lazy.BrowserSearchTelemetry.recordSearchSuggestionSelectionMethod(
|
||||
aEvent,
|
||||
"searchbar",
|
||||
selectedIndex
|
||||
);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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}>
|
||||
|
|
|
@ -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", {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"manifest_version": 2,
|
||||
"name": "New Tab",
|
||||
"description": "",
|
||||
"version": "138.0.0",
|
||||
"version": "139.0.0",
|
||||
|
||||
"browser_specific_settings": {
|
||||
"gecko": {
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -32,6 +32,10 @@
|
|||
&[sidebarcommand="viewGenaiChatSidebar"] {
|
||||
min-width: 400px;
|
||||
}
|
||||
|
||||
&[sidebarcommand="viewCPMSidebar"] {
|
||||
min-width: 260px;
|
||||
}
|
||||
}
|
||||
|
||||
#sidebar-main,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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 {};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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"],
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 state’s 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 loop’s current scheduling state to state.
|
||||
innerWindow->SetWebTaskSchedulingState(newState);
|
||||
callback->Call(*deadline, "requestIdleCallback handler");
|
||||
// Set event loop’s current scheduling state to null.
|
||||
innerWindow->SetWebTaskSchedulingState(nullptr);
|
||||
}
|
||||
|
||||
} // namespace mozilla::dom
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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));
|
||||
};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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 request’s current URL’s
|
||||
// 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)) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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()"));
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -19,6 +19,10 @@ prefs = [
|
|||
|
||||
["test_group_remove.html"]
|
||||
|
||||
["test_pending.html"]
|
||||
|
||||
["test_scenario.html"]
|
||||
|
||||
["test_send_receive.html"]
|
||||
|
||||
["test_utils.html"]
|
||||
|
|
105
dom/mls/tests/test_pending.html
Normal file
105
dom/mls/tests/test_pending.html
Normal 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>
|
101
dom/mls/tests/test_utils.html
Normal file
101
dom/mls/tests/test_utils.html
Normal 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>
|
|
@ -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); }));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 uri’s 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),
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 current’s children:
|
||||
// Step 1. For each child in current’s 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 child’s
|
||||
// Step 1.4.1. Let elementName be a SanitizerElementNamespace with child’s
|
||||
// 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 child’s template contents with
|
||||
// Step 1.4.4.1. Then call sanitize core on child’s 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 child’s
|
||||
// Step 1.4.5. If child is a shadow host, then call sanitize core on child’s
|
||||
// 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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue