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

This commit is contained in:
Cosmin Sabou 2018-11-12 23:56:08 +02:00
Родитель c3a0d1f1bb 124fcbe21d
Коммит a18cb37ca6
61 изменённых файлов: 1103 добавлений и 530 удалений

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

@ -5547,29 +5547,53 @@ var TabContextMenu = {
},
reopenInContainer(event) {
let userContextId = parseInt(event.target.getAttribute("data-usercontextid"));
/* Create a triggering principal that is able to load the new tab
For codebase principals that are about: chrome: or resource: we need system to load them.
Anything other than system principal needs to have the new userContextId.
*/
let triggeringPrincipal = this.contextTab.linkedBrowser.contentPrincipal;
if (triggeringPrincipal.isNullPrincipal) {
triggeringPrincipal = Services.scriptSecurityManager.createNullPrincipal({ userContextId });
} else if (triggeringPrincipal.isCodebasePrincipal) {
triggeringPrincipal = Services.scriptSecurityManager.createCodebasePrincipal(triggeringPrincipal.URI, { userContextId });
}
let newTab = gBrowser.addTab(this.contextTab.linkedBrowser.currentURI.spec, {
userContextId,
pinned: this.contextTab.pinned,
index: this.contextTab._tPos + 1,
triggeringPrincipal,
});
let reopenedTabs = this.contextTab.multiselected ? gBrowser.selectedTabs : [this.contextTab];
if (gBrowser.selectedTab == this.contextTab) {
gBrowser.selectedTab = newTab;
}
if (this.contextTab.muted) {
if (!newTab.muted) {
newTab.toggleMuteAudio(this.contextTab.muteReason);
for (let tab of reopenedTabs) {
if (tab.getAttribute("usercontextid") == userContextId) {
continue;
}
/* Create a triggering principal that is able to load the new tab
For codebase principals that are about: chrome: or resource: we need system to load them.
Anything other than system principal needs to have the new userContextId.
*/
let triggeringPrincipal;
if (tab.linkedPanel) {
triggeringPrincipal = tab.linkedBrowser.contentPrincipal;
} else {
// For lazy tab browsers, get the original principal
// from SessionStore
let tabState = JSON.parse(SessionStore.getTabState(tab));
try {
triggeringPrincipal = Utils.deserializePrincipal(tabState.triggeringPrincipal_base64);
} catch (ex) {
continue;
}
}
if (!triggeringPrincipal || triggeringPrincipal.isNullPrincipal) {
// Ensure that we have a null principal if we couldn't
// deserialize it (for lazy tab browsers) ...
// This won't always work however is safe to use.
triggeringPrincipal = Services.scriptSecurityManager.createNullPrincipal({ userContextId });
} else if (triggeringPrincipal.isCodebasePrincipal) {
triggeringPrincipal = Services.scriptSecurityManager.createCodebasePrincipal(triggeringPrincipal.URI, { userContextId });
}
let newTab = gBrowser.addTab(tab.linkedBrowser.currentURI.spec, {
userContextId,
pinned: tab.pinned,
index: tab._tPos + 1,
triggeringPrincipal,
});
if (gBrowser.selectedTab == tab) {
gBrowser.selectedTab = newTab;
}
if (tab.muted && !newTab.muted) {
newTab.toggleMuteAudio(tab.muteReason);
}
}
},

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

@ -36,6 +36,7 @@ support-files =
[browser_multiselect_tabs_pin_unpin.js]
[browser_multiselect_tabs_positional_attrs.js]
[browser_multiselect_tabs_reload.js]
[browser_multiselect_tabs_reopen_in_container.js]
[browser_multiselect_tabs_reorder.js]
[browser_multiselect_tabs_using_Ctrl.js]
[browser_multiselect_tabs_using_keyboard.js]

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

@ -0,0 +1,108 @@
"use strict";
const PREF_MULTISELECT_TABS = "browser.tabs.multiselect";
const PREF_PRIVACY_USER_CONTEXT_ENABLED = "privacy.userContext.enabled";
async function openTabMenuFor(tab) {
let tabMenu = tab.ownerDocument.getElementById("tabContextMenu");
let tabMenuShown = BrowserTestUtils.waitForEvent(tabMenu, "popupshown");
EventUtils.synthesizeMouseAtCenter(tab, {type: "contextmenu"},
tab.ownerGlobal);
await tabMenuShown;
return tabMenu;
}
async function openReopenMenuForTab(tab) {
openTabMenuFor(tab);
let reopenItem = tab.ownerDocument.getElementById("context_reopenInContainer");
ok(!reopenItem.hidden, "Reopen in Container item should be shown");
let reopenMenu = reopenItem.getElementsByTagName("menupopup")[0];
let reopenMenuShown = BrowserTestUtils.waitForEvent(reopenMenu, "popupshown");
EventUtils.synthesizeMouseAtCenter(reopenItem, {type: "mousemove"},
tab.ownerGlobal);
await reopenMenuShown;
return reopenMenu;
}
function checkMenuItem(reopenMenu, shown, hidden) {
for (let id of shown) {
ok(reopenMenu.querySelector(`menuitem[data-usercontextid="${id}"]`),
`User context id ${id} should exist`);
}
for (let id of hidden) {
ok(!reopenMenu.querySelector(`menuitem[data-usercontextid="${id}"]`),
`User context id ${id} shouldn't exist`);
}
}
function openTabInContainer(gBrowser, tab, reopenMenu, id) {
let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser, getUrl(tab), true);
let menuitem = reopenMenu.querySelector(`menuitem[data-usercontextid="${id}"]`);
EventUtils.synthesizeMouseAtCenter(menuitem, {}, menuitem.ownerGlobal);
return tabPromise;
}
add_task(async function testReopen() {
await SpecialPowers.pushPrefEnv({"set": [
[PREF_PRIVACY_USER_CONTEXT_ENABLED, true],
[PREF_MULTISELECT_TABS, true],
]});
let tab1 = await addTab("http://mochi.test:8888/1");
let tab2 = await addTab("http://mochi.test:8888/2");
let tab3 = await addTab("http://mochi.test:8888/3");
let tab4 = await addTab("http://mochi.test:8888/3", {createLazyBrowser: true});
await BrowserTestUtils.switchTab(gBrowser, tab1);
await triggerClickOn(tab2, { ctrlKey: true });
await triggerClickOn(tab4, { ctrlKey: true });
for (let tab of [tab1, tab2, tab3, tab4]) {
ok(!tab.hasAttribute("usercontextid"),
"Tab with No Container should be opened");
}
ok(tab1.multiselected, "Tab1 is multi-selected");
ok(tab2.multiselected, "Tab2 is multi-selected");
ok(!tab3.multiselected, "Tab3 is not multi-selected");
ok(tab4.multiselected, "Tab4 is multi-selected");
is(gBrowser.visibleTabs.length, 5, "We have 5 tabs open");
let reopenMenu1 = await openReopenMenuForTab(tab1);
checkMenuItem(reopenMenu1, [1, 2, 3, 4], [0]);
let containerTab1 = await openTabInContainer(gBrowser, tab1, reopenMenu1, "1");
let tabs = gBrowser.visibleTabs;
is(tabs.length, 8, "Now we have 8 tabs open");
is(containerTab1._tPos, 2, "containerTab1 position is 3");
is(containerTab1.getAttribute("usercontextid"), "1",
"Tab(1) with UCI=1 should be opened");
is(getUrl(containerTab1), getUrl(tab1),
"Same page (tab1) should be opened");
let containerTab2 = tabs[4];
is(containerTab2.getAttribute("usercontextid"), "1",
"Tab(2) with UCI=1 should be opened");
await TestUtils.waitForCondition(function() {
return getUrl(containerTab2) == getUrl(tab2);
}, "Same page (tab2) should be opened");
let containerTab4 = tabs[7];
is(containerTab2.getAttribute("usercontextid"), "1",
"Tab(4) with UCI=1 should be opened");
await TestUtils.waitForCondition(function() {
return getUrl(containerTab4) == getUrl(tab4);
}, "Same page (tab4) should be opened");
for (let tab of tabs.filter(t => t != tabs[0])) {
BrowserTestUtils.removeTab(tab);
}
});

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

@ -21,8 +21,9 @@ function triggerClickOn(target, options) {
return promise;
}
async function addTab(url = "http://mochi.test:8888/") {
const tab = BrowserTestUtils.addTab(gBrowser, url, { skipAnimation: true });
async function addTab(url = "http://mochi.test:8888/", params = {}) {
params.skipAnimation = true;
const tab = BrowserTestUtils.addTab(gBrowser, url, params);
const browser = gBrowser.getBrowserForTab(tab);
await BrowserTestUtils.browserLoaded(browser);
return tab;

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

@ -37,22 +37,18 @@
</h1>
<section class="section-main">
<p>&aboutPrivateBrowsing.info.notsaved.before;<strong>&aboutPrivateBrowsing.info.notsaved.emphasize;</strong>&aboutPrivateBrowsing.info.notsaved.after;</p>
<div class="list-row">
<ul>
<li>&aboutPrivateBrowsing.info.visited;</li>
<li>&aboutPrivateBrowsing.info.cookies;</li>
<li>&aboutPrivateBrowsing.info.searches;</li>
<li>&aboutPrivateBrowsing.info.temporaryFiles;</li>
</ul>
</div>
<ul class="list-row">
<li>&aboutPrivateBrowsing.info.visited;</li>
<li>&aboutPrivateBrowsing.info.cookies;</li>
<li>&aboutPrivateBrowsing.info.searches;</li>
<li>&aboutPrivateBrowsing.info.temporaryFiles;</li>
</ul>
<p>&aboutPrivateBrowsing.info.saved.before;<strong>&aboutPrivateBrowsing.info.saved.emphasize;</strong>&aboutPrivateBrowsing.info.saved.after2;</p>
<div class="list-row">
<ul>
<li>&aboutPrivateBrowsing.info.bookmarks;</li>
<li>&aboutPrivateBrowsing.info.downloads;</li>
<li>&aboutPrivateBrowsing.info.clipboard;</li>
</ul>
</div>
<ul class="list-row">
<li>&aboutPrivateBrowsing.info.bookmarks;</li>
<li>&aboutPrivateBrowsing.info.downloads;</li>
<li>&aboutPrivateBrowsing.info.clipboard;</li>
</ul>
<p>&aboutPrivateBrowsing.note.before;<strong>&aboutPrivateBrowsing.note.emphasize;</strong>&aboutPrivateBrowsing.note.after;</p>
</section>

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

@ -204,8 +204,8 @@ let URICountListener = {
if (!this.isHttpURI(uri)) {
return;
}
if (shouldRecordSearchCount(browser.getTabBrowser())) {
if (shouldRecordSearchCount(browser.getTabBrowser()) &&
!(flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT)) {
Services.search.recordSearchURLTelemetry(uriSpec);
}

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

@ -8,6 +8,8 @@ html.private {
--in-content-page-color: white;
--in-content-text-color: white;
--in-content-page-background: #25003e;
--in-content-link-color-hover: white;
--in-content-link-color-active: white;
}
a:link {
@ -32,22 +34,25 @@ p {
}
.list-row {
overflow: auto;
display: grid;
column-gap: 2em;
grid-template-columns: repeat(auto-fill, minmax(10em, 16em));
margin-inline-start: 3em;
}
.list-row > ul > li {
float: inline-start;
width: 16em;
line-height: 2em;
margin-inline-start: 1em;
.list-row li {
margin-bottom: 0;
padding: .25em 0;
line-height: 1.5;
}
.title {
background-image: url("chrome://browser/skin/privatebrowsing/private-browsing.svg");
background-position: left center;
background-size: 2em;
line-height: 2em;
line-height: 1.4;
padding-top: 0.3em;
padding-bottom: 0.3em;
margin-inline-start: calc(-2em - 10px);
padding-inline-start: calc(2em + 10px);
}
@ -57,6 +62,7 @@ p {
}
.about-subheader {
--icon-size: 1.5em;
display: flex;
align-items: center;
font-size: 1.5em;
@ -64,22 +70,25 @@ p {
background-image: url("chrome://browser/skin/privatebrowsing/tracking-protection.svg");
background-repeat: no-repeat;
background-position: left center;
background-size: 1.5em;
background-size: var(--icon-size);
line-height: 1.5em;
margin-inline-start: calc(-1.5em - 10px);
padding-inline-start: calc(1.5em + 10px);
margin-inline-start: calc((var(--icon-size) + 10px) * -1);
padding-inline-start: calc(var(--icon-size) + 10px);
}
.about-subheader:dir(rtl) {
background-position: right;
}
.about-info {
font-size: .9em;
@media (max-width: 970px) {
.about-subheader {
--icon-size: 1em;
margin-inline-start: 0;
}
}
#cbTitle {
margin-inline-end: 12px;
.about-info {
font-size: .9em;
}
a.button {
@ -89,3 +98,8 @@ a.button {
text-decoration: none;
display: inline-block;
}
a.button:hover:active {
color: inherit;
background-color: #6000a1;
}

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

@ -8,7 +8,6 @@ import errno
import json
import os
import platform
import random
import subprocess
import sys
import uuid
@ -122,10 +121,6 @@ CATEGORIES = {
}
# We submit data to telemetry approximately every this many mach invocations
TELEMETRY_SUBMISSION_FREQUENCY = 10
def search_path(mozilla_dir, packages_txt):
with open(os.path.join(mozilla_dir, packages_txt)) as f:
packages = [line.rstrip().split(':') for line in f]
@ -278,15 +273,15 @@ def bootstrap(topsrcdir, mozilla_dir=None):
if should_skip_telemetry_submission(handler):
return True
# But only submit about every n-th operation
if random.randint(1, TELEMETRY_SUBMISSION_FREQUENCY) != 1:
return
state_dir, _ = get_state_dir()
machpath = os.path.join(instance.topsrcdir, 'mach')
with open(os.devnull, 'wb') as devnull:
subprocess.Popen([sys.executable,
subprocess.Popen([machpath, 'python',
'--no-virtualenv',
os.path.join(topsrcdir, 'build',
'submit_telemetry_data.py'),
get_state_dir()[0]],
state_dir],
stdout=devnull, stderr=devnull)
def populate_context(context, key=None):

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

@ -10,19 +10,14 @@ import logging
import os
import sys
HERE = os.path.abspath(os.path.dirname(__file__))
PYTHIRDPARTY = os.path.join(HERE, '..', 'third_party', 'python')
# Add some required files to $PATH to ensure they are available
sys.path.append(os.path.join(HERE, '..', 'python', 'mozbuild', 'mozbuild'))
sys.path.append(os.path.join(PYTHIRDPARTY, 'requests'))
sys.path.append(os.path.join(PYTHIRDPARTY, 'voluptuous'))
import requests
import voluptuous
import voluptuous.humanize
from mozbuild.telemetry import schema as build_telemetry_schema
from mozbuild.telemetry import (
schema as build_telemetry_schema,
verify_statedir,
)
BUILD_TELEMETRY_URL = 'https://incoming.telemetry.mozilla.org/{endpoint}'
SUBMIT_ENDPOINT = 'submit/eng-workflow/build/1/{ping_uuid}'
@ -135,35 +130,6 @@ def submit_telemetry_data(outgoing, submitted):
return 0
def verify_statedir(statedir):
'''Verifies the statedir is structured according to the assumptions of
this script
Requires presence of the following directories; will raise if absent:
- statedir/telemetry
- statedir/telemetry/outgoing
Creates the following directories and files if absent (first submission):
- statedir/telemetry/submitted
'''
telemetry_dir = os.path.join(statedir, 'telemetry')
outgoing = os.path.join(telemetry_dir, 'outgoing')
submitted = os.path.join(telemetry_dir, 'submitted')
telemetry_log = os.path.join(telemetry_dir, 'telemetry.log')
if not os.path.isdir(telemetry_dir):
raise Exception('{} does not exist'.format(telemetry_dir))
if not os.path.isdir(outgoing):
raise Exception('{} does not exist'.format(outgoing))
if not os.path.isdir(submitted):
os.mkdir(submitted)
return outgoing, submitted, telemetry_log
if __name__ == '__main__':
if len(sys.argv) != 2:
print('usage: python submit_telemetry_data.py <statedir>')

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

@ -0,0 +1,133 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {
AUTOCOMPLETE_CLEAR,
AUTOCOMPLETE_DATA_RECEIVE,
AUTOCOMPLETE_PENDING_REQUEST,
AUTOCOMPLETE_RETRIEVE_FROM_CACHE,
} = require("devtools/client/webconsole/constants");
/**
* Update the data used for the autocomplete popup in the console input (JsTerm).
*
* @param {Object} Object of the following shape:
* - {String} inputValue: the expression to complete.
* - {Int} cursor: The position of the cursor in the inputValue.
* - {WebConsoleClient} client: The webconsole client.
* - {String} frameActorId: The id of the frame we want to autocomplete in.
* - {Boolean} force: True to force a call to the server (as opposed to retrieve
* from the cache).
*/
function autocompleteUpdate({
inputValue,
cursor,
client,
frameActorId,
force,
}) {
return ({dispatch, getState}) => {
const {cache} = getState().autocomplete;
if (!force && (
!inputValue ||
/^[a-zA-Z0-9_$]/.test(inputValue.substring(cursor))
)) {
return dispatch(autocompleteClear());
}
const input = inputValue.substring(0, cursor);
const retrieveFromCache = !force &&
cache &&
cache.input &&
input.startsWith(cache.input) &&
/[a-zA-Z0-9]$/.test(input) &&
frameActorId === cache.frameActorId;
if (retrieveFromCache) {
return dispatch(autoCompleteDataRetrieveFromCache(input));
}
return dispatch(autocompleteDataFetch({input, frameActorId, client}));
};
}
/**
* Called when the autocompletion data should be cleared.
*/
function autocompleteClear() {
return {
type: AUTOCOMPLETE_CLEAR,
};
}
/**
* Called when the autocompletion data should be retrieved from the cache (i.e.
* client-side).
*
* @param {String} input: The input used to filter the cached data.
*/
function autoCompleteDataRetrieveFromCache(input) {
return {
type: AUTOCOMPLETE_RETRIEVE_FROM_CACHE,
input,
};
}
let currentRequestId = 0;
function generateRequestId() {
return currentRequestId++;
}
/**
* Action that fetch autocompletion data from the server.
*
* @param {Object} Object of the following shape:
* - {String} input: the expression that we want to complete.
* - {String} frameActorId: The id of the frame we want to autocomplete in.
* - {WebConsoleClient} client: The webconsole client.
*/
function autocompleteDataFetch({
input,
frameActorId,
client,
}) {
return ({dispatch}) => {
const id = generateRequestId();
dispatch({type: AUTOCOMPLETE_PENDING_REQUEST, id});
client.autocomplete(input, undefined, frameActorId).then(res => {
dispatch(autocompleteDataReceive(id, input, frameActorId, res));
}).catch(e => {
console.error("failed autocomplete", e);
dispatch(autocompleteClear());
});
};
}
/**
* Called when we receive the autocompletion data from the server.
*
* @param {Integer} id: The autocompletion request id. This will be used in the reducer to
* check that we update the state with the last request results.
* @param {String} input: The expression that was evaluated to get the data.
* - {String} frameActorId: The id of the frame the evaluation was made in.
* @param {Object} data: The actual data sent from the server.
*/
function autocompleteDataReceive(id, input, frameActorId, data) {
return {
type: AUTOCOMPLETE_DATA_RECEIVE,
id,
input,
frameActorId,
data,
};
}
module.exports = {
autocompleteUpdate,
autocompleteDataFetch,
autocompleteDataReceive,
};

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

@ -7,6 +7,7 @@
"use strict";
const actionModules = [
require("./autocomplete"),
require("./filters"),
require("./messages"),
require("./ui"),

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

@ -4,6 +4,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
'autocomplete.js',
'filters.js',
'history.js',
'index.js',

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

@ -39,7 +39,9 @@ const {
getHistory,
getHistoryValue,
} = require("devtools/client/webconsole/selectors/history");
const {getAutocompleteState} = require("devtools/client/webconsole/selectors/autocomplete");
const historyActions = require("devtools/client/webconsole/actions/history");
const autocompleteActions = require("devtools/client/webconsole/actions/autocomplete");
// Constants used for defining the direction of JSTerm input history navigation.
const {
@ -77,6 +79,10 @@ class JSTerm extends Component {
codeMirrorEnabled: PropTypes.bool,
// Update position in the history after executing an expression (action).
updateHistoryPosition: PropTypes.func.isRequired,
// Update autocomplete popup state.
autocompleteUpdate: PropTypes.func.isRequired,
// Data to be displayed in the autocomplete popup.
autocompleteData: PropTypes.object.isRequired,
};
}
@ -94,40 +100,16 @@ class JSTerm extends Component {
this._inputEventHandler = this._inputEventHandler.bind(this);
this._blurEventHandler = this._blurEventHandler.bind(this);
this.onContextMenu = this.onContextMenu.bind(this);
this.imperativeUpdate = this.imperativeUpdate.bind(this);
this.SELECTED_FRAME = -1;
/**
* Array that caches the user input suggestions received from the server.
* @private
* @type array
*/
this._autocompleteCache = null;
/**
* The input that caused the last request to the server, whose response is
* cached in the _autocompleteCache array.
* @private
* @type string
*/
this._autocompleteQuery = null;
/**
* The frameActorId used in the last autocomplete query. Whenever this changes
* the autocomplete cache must be invalidated.
* @private
* @type string
*/
this._lastFrameActorId = null;
/**
* Last input value.
* @type string
*/
this.lastInputValue = "";
this.currentAutoCompletionRequestId = null;
this.autocompletePopup = null;
this.inputNode = null;
this.completeNode = null;
@ -356,7 +338,7 @@ class JSTerm extends Component {
"Ctrl-Space": () => {
if (!this.autocompletePopup.isOpen) {
this.updateAutocompletion(true);
this.fetchAutocompletionProperties(true);
return null;
}
@ -403,13 +385,32 @@ class JSTerm extends Component {
this.lastInputValue && this.setInputValue(this.lastInputValue);
}
shouldComponentUpdate(nextProps, nextState) {
componentWillReceiveProps(nextProps) {
this.imperativeUpdate(nextProps);
}
shouldComponentUpdate(nextProps) {
// XXX: For now, everything is handled in an imperative way and we
// only want React to do the initial rendering of the component.
// This should be modified when the actual refactoring will take place.
return false;
}
/**
* Do all the imperative work needed after a Redux store update.
*
* @param {Object} nextProps: props passed from shouldComponentUpdate.
*/
imperativeUpdate(nextProps) {
if (
nextProps &&
nextProps.autocompleteData !== this.props.autocompleteData &&
nextProps.autocompleteData.pendingRequestId === null
) {
this.updateAutocompletionPopup(nextProps.autocompleteData);
}
}
/**
* Getter for the element that holds the messages we display.
* @type Element
@ -773,7 +774,7 @@ class JSTerm extends Component {
const value = this.getInputValue();
if (this.lastInputValue !== value) {
this.resizeInput();
this.updateAutocompletion();
this.fetchAutocompletionProperties();
this.lastInputValue = value;
}
}
@ -860,7 +861,7 @@ class JSTerm extends Component {
if (event.key === " " && !this.autocompletePopup.isOpen) {
// Open the autocompletion popup on Ctrl-Space (if it wasn't displayed).
this.updateAutocompletion(true);
this.fetchAutocompletionProperties(true);
event.preventDefault();
}
@ -1104,137 +1105,64 @@ class JSTerm extends Component {
}
/**
* Retrieves properties maching the current input for the selected frame, either from
* the server or from a cache if possible.
* Will bail-out if there's some text selection in the input.
*
* @param {Boolean} force: True to not perform any check before trying to show the
* autocompletion popup. Defaults to false.
* @fires autocomplete-updated
* @returns void
*/
async updateAutocompletion(force = false) {
async fetchAutocompletionProperties(force = false) {
const inputValue = this.getInputValue();
const {editor, inputNode} = this;
const frameActor = this.getFrameActor(this.SELECTED_FRAME);
const frameActorId = this.getFrameActor(this.SELECTED_FRAME);
const cursor = this.getSelectionStart();
// Complete if:
// - `force` is true OR
// - The input is not empty
// - AND there is not text selected
// - AND the input or frameActor are different from previous completion
// - AND there is not an alphanumeric (+ "_" and "$") right after the cursor
if (!force && (
!inputValue ||
const {editor, inputNode} = this;
if (
(inputNode && inputNode.selectionStart != inputNode.selectionEnd) ||
(editor && editor.getSelection()) ||
(
!force &&
this.lastInputValue === inputValue &&
frameActor === this._lastFrameActorId
) ||
/^[a-zA-Z0-9_$]/.test(inputValue.substring(cursor))
)) {
(editor && editor.getSelection())
) {
this.clearCompletion();
this.emit("autocomplete-updated");
return;
}
const input = this.getInputValueBeforeCursor();
// If the current input starts with the previous input, then we already
// have a list of suggestions and we just need to filter the cached
// suggestions. When the current input ends with a non-alphanumeric character we ask
// the server again for suggestions.
// Check if last character is non-alphanumeric
if (!/[a-zA-Z0-9]$/.test(input) || frameActor != this._lastFrameActorId) {
this._autocompleteQuery = null;
this._autocompleteCache = null;
}
if (this._autocompleteQuery && input.startsWith(this._autocompleteQuery)) {
let filterBy = input;
if (this._autocompleteCache.isElementAccess) {
// if we're performing an element access, we can simply retrieve whatever comes
// after the last opening bracket.
filterBy = input.substring(input.lastIndexOf("[") + 1);
} else {
// Find the last non-alphanumeric other than "_", ":", or "$" if it exists.
const lastNonAlpha = input.match(/[^a-zA-Z0-9_$:][a-zA-Z0-9_$:]*$/);
// If input contains non-alphanumerics, use the part after the last one
// to filter the cache.
if (lastNonAlpha) {
filterBy = input.substring(input.lastIndexOf(lastNonAlpha) + 1);
}
}
const stripWrappingQuotes = s => s.replace(/^['"`](.+(?=['"`]$))['"`]$/g, "$1");
const filterByLc = filterBy.toLocaleLowerCase();
const looseMatching = !filterBy || filterBy[0].toLocaleLowerCase() === filterBy[0];
const needStripQuote = this._autocompleteCache.isElementAccess
&& !/^[`"']/.test(filterBy);
const newList = this._autocompleteCache.matches.filter(l => {
if (needStripQuote) {
l = stripWrappingQuotes(l);
}
if (looseMatching) {
return l.toLocaleLowerCase().startsWith(filterByLc);
}
return l.startsWith(filterBy);
});
this._receiveAutocompleteProperties(null, {
matches: newList,
matchProp: filterBy,
isElementAccess: this._autocompleteCache.isElementAccess,
});
return;
}
const requestId = gSequenceId();
this._lastFrameActorId = frameActor;
this.currentAutoCompletionRequestId = requestId;
const message = await this.webConsoleClient.autocomplete(input, cursor, frameActor);
this._receiveAutocompleteProperties(requestId, message);
this.props.autocompleteUpdate({
inputValue,
cursor,
frameActorId,
force,
client: this.webConsoleClient,
});
}
/**
* Handler for the autocompletion results. This method takes
* the completion result received from the server and updates the UI
* accordingly.
* Takes the data returned by the server and update the autocomplete popup state (i.e.
* its visibility and items).
*
* @param number requestId
* Request ID.
* @param object message
* The JSON message which holds the completion results received from
* the content process.
* @param {Object} data
* The autocompletion data as returned by the webconsole actor's autocomplete
* service. Should be of the following shape:
* {
* matches: {Array} array of the properties matching the input,
* matchProp: {String} The string used to filter the properties,
* isElementAccess: {Boolean} True when the input is an element access,
* i.e. `document["addEve`.
* }
* @fires autocomplete-updated
*/
_receiveAutocompleteProperties(requestId, message) {
if (this.currentAutoCompletionRequestId !== requestId) {
return;
}
this.currentAutoCompletionRequestId = null;
// Cache whatever came from the server if the last char is
// alphanumeric, '.' or '['.
const inputUntilCursor = this.getInputValueBeforeCursor();
if (requestId != null && /[a-zA-Z0-9.\[]$/.test(inputUntilCursor)) {
this._autocompleteCache = {
matches: message.matches,
matchProp: message.matchProp,
isElementAccess: message.isElementAccess,
};
this._autocompleteQuery = inputUntilCursor;
}
const {matches, matchProp, isElementAccess} = message;
updateAutocompletionPopup(data) {
const {matches, matchProp, isElementAccess} = data;
if (!matches.length) {
this.clearCompletion();
this.emit("autocomplete-updated");
return;
}
const inputUntilCursor = this.getInputValueBeforeCursor();
const items = matches.map(label => {
let preLabel = label.substring(0, matchProp.length);
// If the user is performing an element access, and if they did not typed a quote,
@ -1673,15 +1601,27 @@ function mapStateToProps(state) {
return {
history: getHistory(state),
getValueFromHistory: (direction) => getHistoryValue(state, direction),
autocompleteData: getAutocompleteState(state),
};
}
function mapDispatchToProps(dispatch) {
return {
appendToHistory: (expr) => dispatch(historyActions.appendToHistory(expr)),
clearHistory: () => dispatch(historyActions.clearHistory()),
updateHistoryPosition: (direction, expression) =>
dispatch(historyActions.updateHistoryPosition(direction, expression)),
autocompleteUpdate: ({inputValue, cursor, frameActorId, force, client}) => dispatch(
autocompleteActions.autocompleteUpdate({
inputValue,
cursor,
frameActorId,
force,
client,
})
),
autocompleteBailOut: () => dispatch(autocompleteActions.autocompleteBailOut()),
};
}

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

@ -8,6 +8,10 @@
const actionTypes = {
APPEND_NOTIFICATION: "APPEND_NOTIFICATION",
APPEND_TO_HISTORY: "APPEND_TO_HISTORY",
AUTOCOMPLETE_CLEAR: "AUTOCOMPLETE_CLEAR",
AUTOCOMPLETE_DATA_RECEIVE: "AUTOCOMPLETE_DATA_RECEIVE",
AUTOCOMPLETE_PENDING_REQUEST: "AUTOCOMPLETE_PENDING_REQUEST",
AUTOCOMPLETE_RETRIEVE_FROM_CACHE: "AUTOCOMPLETE_RETRIEVE_FROM_CACHE",
BATCH_ACTIONS: "BATCH_ACTIONS",
CLEAR_HISTORY: "CLEAR_HISTORY",
DEFAULT_FILTERS_RESET: "DEFAULT_FILTERS_RESET",

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

@ -0,0 +1,104 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {
AUTOCOMPLETE_CLEAR,
AUTOCOMPLETE_DATA_RECEIVE,
AUTOCOMPLETE_PENDING_REQUEST,
AUTOCOMPLETE_RETRIEVE_FROM_CACHE,
} = require("devtools/client/webconsole/constants");
function getDefaultState() {
return Object.freeze({
cache: null,
matches: [],
matchProp: null,
isElementAccess: false,
pendingRequestId: null,
});
}
function autocomplete(state = getDefaultState(), action) {
switch (action.type) {
case AUTOCOMPLETE_CLEAR:
return getDefaultState();
case AUTOCOMPLETE_RETRIEVE_FROM_CACHE:
return autoCompleteRetrieveFromCache(state, action);
case AUTOCOMPLETE_PENDING_REQUEST:
return {
...state,
cache: null,
pendingRequestId: action.id,
};
case AUTOCOMPLETE_DATA_RECEIVE:
if (action.id !== state.pendingRequestId) {
return state;
}
return {
...state,
cache: {
input: action.input,
frameActorId: action.frameActorId,
...action.data,
},
pendingRequestId: null,
...action.data,
};
}
return state;
}
/**
* Retrieve from cache action reducer.
*
* @param {Object} state
* @param {Object} action
* @returns {Object} new state.
*/
function autoCompleteRetrieveFromCache(state, action) {
const {input} = action;
const {cache} = state;
let filterBy = input;
if (cache.isElementAccess) {
// if we're performing an element access, we can simply retrieve whatever comes
// after the last opening bracket.
filterBy = input.substring(input.lastIndexOf("[") + 1);
} else {
// Find the last non-alphanumeric other than "_", ":", or "$" if it exists.
const lastNonAlpha = input.match(/[^a-zA-Z0-9_$:][a-zA-Z0-9_$:]*$/);
// If input contains non-alphanumerics, use the part after the last one
// to filter the cache.
if (lastNonAlpha) {
filterBy = input.substring(input.lastIndexOf(lastNonAlpha) + 1);
}
}
const stripWrappingQuotes = s => s.replace(/^['"`](.+(?=['"`]$))['"`]$/g, "$1");
const filterByLc = filterBy.toLocaleLowerCase();
const looseMatching = !filterBy || filterBy[0].toLocaleLowerCase() === filterBy[0];
const needStripQuote = cache.isElementAccess && !/^[`"']/.test(filterBy);
const newList = cache.matches.filter(l => {
if (needStripQuote) {
l = stripWrappingQuotes(l);
}
if (looseMatching) {
return l.toLocaleLowerCase().startsWith(filterByLc);
}
return l.startsWith(filterBy);
});
return {
...state,
matches: newList,
matchProp: filterBy,
isElementAccess: cache.isElementAccess,
};
}
exports.autocomplete = autocomplete;

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

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { autocomplete } = require("./autocomplete");
const { filters } = require("./filters");
const { messages } = require("./messages");
const { prefs } = require("./prefs");
@ -15,6 +16,7 @@ const { history } = require("./history");
const { objectInspector } = require("devtools/client/shared/components/reps/reps.js");
exports.reducers = {
autocomplete,
filters,
messages,
prefs,

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

@ -4,6 +4,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
'autocomplete.js',
'filters.js',
'history.js',
'index.js',

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

@ -0,0 +1,13 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
function getAutocompleteState(state) {
return state.autocomplete;
}
module.exports = {
getAutocompleteState,
};

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

@ -4,6 +4,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
'autocomplete.js',
'filters.js',
'history.js',
'messages.js',

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

@ -20,7 +20,7 @@ add_task(async function() {
});
async function performTests() {
const { jsterm } = await openNewTabAndConsole(TEST_URI);
const { jsterm, ui } = await openNewTabAndConsole(TEST_URI);
const { autocompletePopup: popup } = jsterm;
@ -33,7 +33,7 @@ async function performTests() {
await onPopupOpen;
ok(popup.isOpen, "popup is open");
const cacheMatches = jsterm._autocompleteCache.matches;
const cacheMatches = ui.consoleOutput.getStore().getState().autocomplete.cache.matches;
is(popup.itemCount, cacheMatches.length, "popup.itemCount is correct");
ok(cacheMatches.includes("addEventListener"),
"addEventListener is in the list of suggestions");

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

@ -449,6 +449,13 @@ WebConsoleOutputWrapper.prototype = {
setTimeout(() => {
this.throttledDispatchPromise = null;
if (!store) {
// The store is not initialized yet, we can call setTimeoutIfNeeded so the
// messages will be handled in the next timeout when the store is ready.
this.setTimeoutIfNeeded();
return;
}
store.dispatch(actions.messagesAdd(this.queuedMessageAdds));
const length = this.queuedMessageAdds.length;

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

@ -20,6 +20,8 @@ const { Services } = jsmScope;
// Steal various globals only available in JSM scope (and not Sandbox one)
const {
console,
DOMPoint,
DOMQuad,
HeapSnapshot,
StructuredCloneHolder,
TelemetryStopwatch,
@ -283,6 +285,8 @@ exports.globals = {
factory(this.require, this.exports, this.module);
},
DOMParser,
DOMPoint,
DOMQuad,
Element,
Event,
FormData,

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

@ -98,6 +98,7 @@ add_task(async function() {
let topContext = getBrowsingContextById(topId);
isnot(topContext, null);
is(topContext.parent, null);
is(topId, browser.browsingContext.id, "<browser> has the correct browsingContext");
let id0 = await addFrame(browser, "frame0");
let browsingContext0 = getBrowsingContextById(id0);

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

@ -782,6 +782,12 @@ ChromeUtils::RequestIOActivity(GlobalObject& aGlobal, ErrorResult& aRv)
return domPromise.forget();
}
/* static */ already_AddRefed<BrowsingContext>
ChromeUtils::GetBrowsingContext(GlobalObject& aGlobal, uint64_t id)
{
return BrowsingContext::Get(id);
}
/* static */ void
ChromeUtils::GetRootBrowsingContexts(GlobalObject& aGlobal,
nsTArray<RefPtr<BrowsingContext>>& aBrowsingContexts)

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

@ -189,6 +189,9 @@ public:
static already_AddRefed<Promise>
RequestIOActivity(GlobalObject& aGlobal, ErrorResult& aRv);
static already_AddRefed<BrowsingContext>
GetBrowsingContext(GlobalObject& aGlobal, uint64_t id);
static void
GetRootBrowsingContexts(GlobalObject& aGlobal,
nsTArray<RefPtr<BrowsingContext>>& aBrowsingContexts);

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

@ -140,7 +140,7 @@ ElemBaseType(const GLenum elemType)
case LOCAL_GL_BOOL_VEC2:
case LOCAL_GL_BOOL_VEC3:
case LOCAL_GL_BOOL_VEC4:
return webgl::AttribBaseType::Bool;
return webgl::AttribBaseType::Boolean;
// -

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

@ -859,7 +859,7 @@ WebGLContext::DoFakeVertexAttrib0(const uint64_t vertexCount)
////
switch (mGenericVertexAttribTypes[0]) {
case webgl::AttribBaseType::Bool:
case webgl::AttribBaseType::Boolean:
case webgl::AttribBaseType::Float:
gl->fVertexAttribPointer(0, 4, LOCAL_GL_FLOAT, false, 0, 0);
break;

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

@ -255,7 +255,7 @@ WebGLContext::GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname,
obj = GetVertexAttribUint32Array(cx, index);
break;
case webgl::AttribBaseType::Bool:
case webgl::AttribBaseType::Boolean:
MOZ_CRASH("impossible");
}

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

@ -474,7 +474,7 @@ webgl::ToString(const webgl::AttribBaseType x)
return "INT";
case webgl::AttribBaseType::UInt:
return "UINT";
case webgl::AttribBaseType::Bool:
case webgl::AttribBaseType::Boolean:
return "BOOL";
}
MOZ_CRASH("pacify gcc6 warning");
@ -554,7 +554,7 @@ webgl::LinkedProgramInfo::GetDrawFetchLimits() const
const auto& progBaseType = progAttrib.mActiveInfo->mBaseType;
if ((attribDataBaseType != progBaseType) &
(progBaseType != webgl::AttribBaseType::Bool))
(progBaseType != webgl::AttribBaseType::Boolean))
{
const auto& dataType = ToString(attribDataBaseType);
const auto& progType = ToString(progBaseType);

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

@ -193,7 +193,7 @@ enum class AttribBaseType : uint8_t {
Int,
UInt,
Float, // Also includes NormU?Int
Bool, // Can convert from anything.
Boolean, // Can convert from anything.
};
const char* ToString(AttribBaseType);

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

@ -62,7 +62,7 @@ WebGLUniformLocation::ValidateSizeAndType(const uint8_t setterElemSize,
const auto& uniformType = mInfo->mActiveInfo->mBaseType;
if (setterType != uniformType &&
uniformType != webgl::AttribBaseType::Bool)
uniformType != webgl::AttribBaseType::Boolean)
{
const auto& uniformStr = EnumString(mInfo->mActiveInfo->mElemType);
mContext->ErrorInvalidOperation("Function used is incompatible with uniform"

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

@ -356,6 +356,15 @@ partial namespace ChromeUtils {
[Throws]
Promise<sequence<IOActivityDataDictionary>> requestIOActivity();
/**
* Returns the BrowsingContext referred by the given id.
*/
[ChromeOnly]
BrowsingContext? getBrowsingContext(unsigned long long id);
/**
* Returns all the root BrowsingContexts.
*/
[ChromeOnly]
sequence<BrowsingContext> getRootBrowsingContexts();
};

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

@ -91,6 +91,10 @@ IsWindowAllowedToPlay(nsPIDOMWindowInner* aWindow)
}
nsIDocument* approver = ApproverDocOf(*aWindow->GetExtantDoc());
if (!approver) {
return false;
}
if (nsContentUtils::IsExactSitePermAllow(approver->NodePrincipal(),
"autoplay-media")) {
AUTOPLAY_LOG("Allow autoplay as document has autoplay permission.");
@ -163,12 +167,6 @@ IsMediaElementAllowedToPlay(const HTMLMediaElement& aElement)
return true;
}
if (!aElement.HasAudio() &&
aElement.ReadyState() >= HTMLMediaElement_Binding::HAVE_METADATA) {
AUTOPLAY_LOG("Allow media without audio track %p to autoplay\n", &aElement);
return true;
}
return false;
}

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

@ -323,16 +323,16 @@ pub fn tiles(
// Since we're working in layer space, we can end up computing leftover tiles with an empty
// size due to floating point precision issues. Detect this case so that we don't return
// tiles with an empty size.
let x_count = {
let result = f32::ceil((visible_rect.max_x() - prim_rect.origin.x) / layer_tile_size.width) as u32 - t0.x;
let x_max = {
let result = f32::ceil((visible_rect.max_x() - prim_rect.origin.x) / layer_tile_size.width) as u32;
if result == leftover_offset.x + 1 && leftover_layer_size.width == 0.0f32 {
leftover_offset.x
} else {
result
}
};
let y_count = {
let result = f32::ceil((visible_rect.max_y() - prim_rect.origin.y) / layer_tile_size.height) as u32 - t0.y;
let y_max = {
let result = f32::ceil((visible_rect.max_y() - prim_rect.origin.y) / layer_tile_size.height) as u32;
if result == leftover_offset.y + 1 && leftover_layer_size.height == 0.0f32 {
leftover_offset.y
} else {
@ -341,14 +341,14 @@ pub fn tiles(
};
let mut row_flags = EdgeAaSegmentMask::TOP;
if y_count == 1 {
if y_max - t0.y == 1 {
row_flags |= EdgeAaSegmentMask::BOTTOM;
}
TileIterator {
current_x: 0,
current_y: 0,
x_count,
y_count,
x_count: x_max - t0.x,
y_count: y_max - t0.y,
row_flags,
origin: t0,
tile_size: layer_tile_size,

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

@ -1018,6 +1018,8 @@ impl ResourceCache {
}
};
assert!(descriptor.size.width != 0 && descriptor.size.height != 0);
self.missing_blob_images.push(
BlobImageParams {
request,

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

@ -1 +1 @@
d9bddae3796e782548b9f3dfffdbcb26cf719232
45498e55dbb918f82e9583d03912b73b5a301a30

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

@ -6,6 +6,7 @@
package org.mozilla.geckoview;
import android.support.annotation.AnyThread;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
@ -35,6 +36,7 @@ import org.mozilla.gecko.annotation.WrapForJNI;
* });
* </pre>
*/
@AnyThread
public class GeckoWebExecutor {
// We don't use this right now because we access GeckoThread directly, but
// it's future-proofing for a world where we allow multiple GeckoRuntimes.

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

@ -10891,6 +10891,11 @@ square7.net
// Submitted by Dave Tharp <browsersafetymark.io@quicinc.com>
browsersafetymark.io
// Bytemark Hosting : https://www.bytemark.co.uk
// Submitted by Paul Cammish <paul.cammish@bytemark.co.uk>
dh.bytemark.co.uk
vm.bytemark.co.uk
// callidomus : https://www.callidomus.com/
// Submitted by Marcus Popp <admin@callidomus.com>
mycd.eu

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

@ -66,10 +66,6 @@ public final class Portability {
return string.toCharArray();
}
public static @Local String newLocalFromLocal(@Local String local, Interner interner) {
return local;
}
// Deallocation methods
public static void releaseString(String str) {

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

@ -6859,13 +6859,7 @@ public class Tokenizer implements Locator {
seenDigits = other.seenDigits;
endTag = other.endTag;
shouldSuspend = false;
if (other.doctypeName == null) {
doctypeName = null;
} else {
doctypeName = Portability.newLocalFromLocal(other.doctypeName,
interner);
}
doctypeName = other.doctypeName;
Portability.releaseString(systemIdentifier);
if (other.systemIdentifier == null) {
@ -6890,7 +6884,7 @@ public class Tokenizer implements Locator {
// In the C++ case, the atoms in the other tokenizer are from a
// different tokenizer-scoped atom table. Therefore, we have to
// obtain the correspoding atom from our own atom table.
nonInternedTagName.setNameForNonInterned(Portability.newLocalFromLocal(other.tagName.getName(), interner)
nonInternedTagName.setNameForNonInterned(other.tagName.getName()
// CPPONLY: , other.tagName.isCustom()
);
tagName = nonInternedTagName;
@ -6907,7 +6901,7 @@ public class Tokenizer implements Locator {
// CPPONLY: // In the C++ case, the atoms in the other tokenizer are from a
// CPPONLY: // different tokenizer-scoped atom table. Therefore, we have to
// CPPONLY: // obtain the correspoding atom from our own atom table.
// CPPONLY: nonInternedAttributeName.setNameForNonInterned(Portability.newLocalFromLocal(other.attributeName.getLocal(AttributeName.HTML), interner));
// CPPONLY: nonInternedAttributeName.setNameForNonInterned(other.attributeName.getLocal(AttributeName.HTML));
// CPPONLY: attributeName = nonInternedAttributeName;
// CPPONLY: }
@ -6915,7 +6909,7 @@ public class Tokenizer implements Locator {
if (other.attributes == null) {
attributes = null;
} else {
attributes = other.attributes.cloneAttributes(interner);
attributes = other.attributes.cloneAttributes();
}
}
@ -7151,8 +7145,9 @@ public class Tokenizer implements Locator {
void destructor() {
Portability.delete(nonInternedTagName);
// CPPONLY: Portability.delete(nonInternedAttributeName);
nonInternedTagName = null;
// CPPONLY: Portability.delete(nonInternedAttributeName);
// CPPONLY: nonInternedAttributeName = null;
// The translator will write refcount tracing stuff here
Portability.delete(attributes);
attributes = null;

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

@ -4786,7 +4786,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
assert node == listOfActiveFormattingElements[nodeListPos];
assert node == stack[nodePos];
T clone = createElement("http://www.w3.org/1999/xhtml",
node.name, node.attributes.cloneAttributes(null), commonAncestor.node
node.name, node.attributes.cloneAttributes(), commonAncestor.node
// CPPONLY: , htmlCreator(node.getHtmlCreator())
);
StackNode<T> newNode = createStackNode(node.getFlags(), node.ns,
@ -4818,7 +4818,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
}
T clone = createElement("http://www.w3.org/1999/xhtml",
formattingElt.name,
formattingElt.attributes.cloneAttributes(null), furthestBlock.node
formattingElt.attributes.cloneAttributes(), furthestBlock.node
// CPPONLY: , htmlCreator(formattingElt.getHtmlCreator())
);
StackNode<T> formattingClone = createStackNode(
@ -5005,12 +5005,12 @@ public abstract class TreeBuilder<T> implements TokenHandler,
T clone;
if (currentNode.isFosterParenting()) {
clone = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", entry.name,
entry.attributes.cloneAttributes(null)
entry.attributes.cloneAttributes()
// CPPONLY: , htmlCreator(entry.getHtmlCreator())
);
} else {
clone = createElement("http://www.w3.org/1999/xhtml", entry.name,
entry.attributes.cloneAttributes(null), currentNode.node
entry.attributes.cloneAttributes(), currentNode.node
// CPPONLY: , htmlCreator(entry.getHtmlCreator())
);
appendElement(clone, currentNode.node);
@ -5424,7 +5424,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
checkAttributes(attributes, "http://www.w3.org/1999/xhtml");
// ]NOCPP]
// This method can't be called for custom elements
HtmlAttributes clone = attributes.cloneAttributes(null);
HtmlAttributes clone = attributes.cloneAttributes();
// Attributes must not be read after calling createElement, because
// createElement may delete attributes in C++.
T elt;
@ -6130,7 +6130,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
StackNode<T> newNode = new StackNode<T>(-1);
newNode.setValues(node.getFlags(), node.ns,
node.name, node.node, node.popName,
node.attributes.cloneAttributes(null)
node.attributes.cloneAttributes()
// CPPONLY: , node.getHtmlCreator()
// [NOCPP[
, node.getLocator()
@ -6217,7 +6217,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
}
@SuppressWarnings("unchecked") public void loadState(
TreeBuilderState<T> snapshot, Interner interner)
TreeBuilderState<T> snapshot)
throws SAXException {
// CPPONLY: mCurrentHtmlScriptIsAsyncOrDefer = false;
StackNode<T>[] stackCopy = snapshot.getStack();
@ -6254,9 +6254,9 @@ public abstract class TreeBuilder<T> implements TokenHandler,
StackNode<T> node = listCopy[i];
if (node != null) {
StackNode<T> newNode = createStackNode(node.getFlags(), node.ns,
Portability.newLocalFromLocal(node.name, interner), node.node,
Portability.newLocalFromLocal(node.popName, interner),
node.attributes.cloneAttributes(null)
node.name, node.node,
node.popName,
node.attributes.cloneAttributes()
// CPPONLY: , node.getHtmlCreator()
// [NOCPP[
, node.getLocator()
@ -6272,8 +6272,8 @@ public abstract class TreeBuilder<T> implements TokenHandler,
int listIndex = findInArray(node, listCopy);
if (listIndex == -1) {
StackNode<T> newNode = createStackNode(node.getFlags(), node.ns,
Portability.newLocalFromLocal(node.name, interner), node.node,
Portability.newLocalFromLocal(node.popName, interner),
node.name, node.node,
node.popName,
null
// CPPONLY: , node.getHtmlCreator()
// [NOCPP[

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

@ -57,26 +57,12 @@ public:
inline void ReleaseValue() { mValue.Release(); }
inline nsHtml5AttributeEntry Clone(nsHtml5AtomTable* aInterner)
inline nsHtml5AttributeEntry Clone()
{
// Copy the memory
nsHtml5AttributeEntry clone(*this);
// Increment refcount for value
clone.mValue = this->mValue.Clone();
if (aInterner) {
// Now if we have an interner, we'll need to rewrite non-static atoms.
// Only the local names may be non-static, in which case all three
// are the same.
nsAtom* local = GetLocal(0);
if (!local->IsStatic()) {
nsAutoString str;
local->ToString(str);
nsAtom* local = aInterner->GetAtom(str);
clone.mLocals[0] = local;
clone.mLocals[1] = local;
clone.mLocals[2] = local;
}
}
return clone;
}

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

@ -64,7 +64,6 @@ private:
static int32_t* XLINK_NS;
public:
static nsStaticAtom** ALL_NO_PREFIX;
private:
static nsStaticAtom** XMLNS_PREFIX;
static nsStaticAtom** XLINK_PREFIX;
@ -72,7 +71,6 @@ private:
static RefPtr<nsAtom>* SVG_DIFFERENT(nsAtom* name, nsAtom* camel);
static RefPtr<nsAtom>* MATH_DIFFERENT(nsAtom* name, nsAtom* camel);
static RefPtr<nsAtom>* COLONIFIED_LOCAL(nsAtom* name, nsAtom* suffix);
public:
static RefPtr<nsAtom>* SAME_LOCAL(nsAtom* name);
inline static int32_t levelOrderBinarySearch(jArray<int32_t, int32_t> data,

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

@ -200,13 +200,13 @@ nsHtml5HtmlAttributes::adjustForSvg()
}
nsHtml5HtmlAttributes*
nsHtml5HtmlAttributes::cloneAttributes(nsHtml5AtomTable* aInterner)
nsHtml5HtmlAttributes::cloneAttributes()
{
MOZ_ASSERT(mStorage.IsEmpty() || !mMode);
nsHtml5HtmlAttributes* clone =
new nsHtml5HtmlAttributes(nsHtml5AttributeName::HTML);
for (nsHtml5AttributeEntry& entry : mStorage) {
clone->AddEntry(entry.Clone(aInterner));
clone->AddEntry(entry.Clone());
}
return clone;
}

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

@ -87,7 +87,7 @@ public:
bool contains(nsHtml5AttributeName* aName);
void adjustForMath();
void adjustForSvg();
nsHtml5HtmlAttributes* cloneAttributes(nsHtml5AtomTable* aInterner);
nsHtml5HtmlAttributes* cloneAttributes();
bool equalsAnother(nsHtml5HtmlAttributes* aOther);
static void initializeStatics();
static void releaseStatics();

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

@ -478,7 +478,7 @@ nsHtml5Parser::Parse(const nsAString& aSourceBuffer,
mDocWriteSpeculativeTokenizer->start();
}
mDocWriteSpeculativeTokenizer->resetToDataState();
mDocWriteSpeculativeTreeBuilder->loadState(mTreeBuilder, &mAtomTable);
mDocWriteSpeculativeTreeBuilder->loadState(mTreeBuilder);
mDocWriteSpeculativeLastWasCR = false;
}
@ -752,7 +752,7 @@ nsHtml5Parser::InitializeDocWriteParserState(nsAHtml5TreeBuilderState* aState,
{
mTokenizer->resetToDataState();
mTokenizer->setLineNumber(aLine);
mTreeBuilder->loadState(aState, &mAtomTable);
mTreeBuilder->loadState(aState);
mLastWasCR = false;
mReturnToStreamParserPermitted = true;
}

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

@ -17,14 +17,6 @@ nsHtml5Portability::newLocalNameFromBuffer(char16_t* buf,
return interner->GetAtom(nsDependentSubstring(buf, buf + length));
}
nsAtom*
nsHtml5Portability::newLocalFromLocal(nsAtom* local,
nsHtml5AtomTable* interner)
{
// FIXME(emilio): This function should be removed.
return local;
}
static bool
ContainsWhiteSpace(mozilla::Span<char16_t> aSpan)
{

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

@ -69,7 +69,6 @@ public:
static nsHtml5String newStringFromString(nsHtml5String string);
static jArray<char16_t, int32_t> newCharArrayFromLocal(nsAtom* local);
static jArray<char16_t, int32_t> newCharArrayFromString(nsHtml5String string);
static nsAtom* newLocalFromLocal(nsAtom* local, nsHtml5AtomTable* interner);
static bool localEqualsBuffer(nsAtom* local, char16_t* buf, int32_t length);
static bool lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
const char* lowerCaseLiteral,

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

@ -1685,7 +1685,7 @@ nsHtml5StreamParser::ContinueAfterScripts(nsHtml5Tokenizer* aTokenizer,
// Copy state over
mLastWasCR = aLastWasCR;
mTokenizer->loadState(aTokenizer);
mTreeBuilder->loadState(aTreeBuilder, &mAtomTable);
mTreeBuilder->loadState(aTreeBuilder);
} else {
// We've got a successful speculation and at least a moment ago it was
// the current speculation

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

@ -4793,12 +4793,7 @@ nsHtml5Tokenizer::loadState(nsHtml5Tokenizer* other)
seenDigits = other->seenDigits;
endTag = other->endTag;
shouldSuspend = false;
if (!other->doctypeName) {
doctypeName = nullptr;
} else {
doctypeName =
nsHtml5Portability::newLocalFromLocal(other->doctypeName, interner);
}
doctypeName = other->doctypeName;
systemIdentifier.Release();
if (!other->systemIdentifier) {
systemIdentifier = nullptr;
@ -4819,10 +4814,8 @@ nsHtml5Tokenizer::loadState(nsHtml5Tokenizer* other)
} else if (other->tagName->isInterned()) {
tagName = other->tagName;
} else {
nonInternedTagName->setNameForNonInterned(
nsHtml5Portability::newLocalFromLocal(other->tagName->getName(),
interner),
other->tagName->isCustom());
nonInternedTagName->setNameForNonInterned(other->tagName->getName(),
other->tagName->isCustom());
tagName = nonInternedTagName;
}
if (!other->attributeName) {
@ -4831,15 +4824,14 @@ nsHtml5Tokenizer::loadState(nsHtml5Tokenizer* other)
attributeName = other->attributeName;
} else {
nonInternedAttributeName->setNameForNonInterned(
nsHtml5Portability::newLocalFromLocal(
other->attributeName->getLocal(nsHtml5AttributeName::HTML), interner));
other->attributeName->getLocal(nsHtml5AttributeName::HTML));
attributeName = nonInternedAttributeName;
}
delete attributes;
if (!other->attributes) {
attributes = nullptr;
} else {
attributes = other->attributes->cloneAttributes(interner);
attributes = other->attributes->cloneAttributes();
}
}
@ -4864,8 +4856,9 @@ nsHtml5Tokenizer::~nsHtml5Tokenizer()
{
MOZ_COUNT_DTOR(nsHtml5Tokenizer);
delete nonInternedTagName;
delete nonInternedAttributeName;
nonInternedTagName = nullptr;
delete nonInternedAttributeName;
nonInternedAttributeName = nullptr;
delete attributes;
attributes = nullptr;
}

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

@ -3883,7 +3883,7 @@ nsHtml5TreeBuilder::adoptionAgencyEndTag(nsAtom* name)
nsIContentHandle* clone =
createElement(kNameSpaceID_XHTML,
node->name,
node->attributes->cloneAttributes(nullptr),
node->attributes->cloneAttributes(),
commonAncestor->node,
htmlCreator(node->getHtmlCreator()));
nsHtml5StackNode* newNode = createStackNode(node->getFlags(),
@ -3915,7 +3915,7 @@ nsHtml5TreeBuilder::adoptionAgencyEndTag(nsAtom* name)
nsIContentHandle* clone =
createElement(kNameSpaceID_XHTML,
formattingElt->name,
formattingElt->attributes->cloneAttributes(nullptr),
formattingElt->attributes->cloneAttributes(),
furthestBlock->node,
htmlCreator(formattingElt->getHtmlCreator()));
nsHtml5StackNode* formattingClone =
@ -4101,12 +4101,12 @@ nsHtml5TreeBuilder::reconstructTheActiveFormattingElements()
clone = createAndInsertFosterParentedElement(
kNameSpaceID_XHTML,
entry->name,
entry->attributes->cloneAttributes(nullptr),
entry->attributes->cloneAttributes(),
htmlCreator(entry->getHtmlCreator()));
} else {
clone = createElement(kNameSpaceID_XHTML,
entry->name,
entry->attributes->cloneAttributes(nullptr),
entry->attributes->cloneAttributes(),
currentNode->node,
htmlCreator(entry->getHtmlCreator()));
appendElement(clone, currentNode->node);
@ -4391,7 +4391,7 @@ nsHtml5TreeBuilder::appendToCurrentNodeAndPushFormattingElementMayFoster(
nsHtml5ElementName* elementName,
nsHtml5HtmlAttributes* attributes)
{
nsHtml5HtmlAttributes* clone = attributes->cloneAttributes(nullptr);
nsHtml5HtmlAttributes* clone = attributes->cloneAttributes();
nsIContentHandle* elt;
nsHtml5StackNode* current = stack[currentPtr];
if (current->isFosterParenting()) {
@ -4835,7 +4835,7 @@ nsHtml5TreeBuilder::newSnapshot()
node->name,
node->node,
node->popName,
node->attributes->cloneAttributes(nullptr),
node->attributes->cloneAttributes(),
node->getHtmlCreator());
listCopy[i] = newNode;
} else {
@ -4926,8 +4926,7 @@ nsHtml5TreeBuilder::snapshotMatches(nsAHtml5TreeBuilderState* snapshot)
}
void
nsHtml5TreeBuilder::loadState(nsAHtml5TreeBuilderState* snapshot,
nsHtml5AtomTable* interner)
nsHtml5TreeBuilder::loadState(nsAHtml5TreeBuilderState* snapshot)
{
mCurrentHtmlScriptIsAsyncOrDefer = false;
jArray<nsHtml5StackNode*, int32_t> stackCopy = snapshot->getStack();
@ -4963,14 +4962,14 @@ nsHtml5TreeBuilder::loadState(nsAHtml5TreeBuilderState* snapshot,
for (int32_t i = 0; i < listLen; i++) {
nsHtml5StackNode* node = listCopy[i];
if (node) {
nsHtml5StackNode* newNode = createStackNode(
node->getFlags(),
node->ns,
nsHtml5Portability::newLocalFromLocal(node->name, interner),
node->node,
nsHtml5Portability::newLocalFromLocal(node->popName, interner),
node->attributes->cloneAttributes(nullptr),
node->getHtmlCreator());
nsHtml5StackNode* newNode =
createStackNode(node->getFlags(),
node->ns,
node->name,
node->node,
node->popName,
node->attributes->cloneAttributes(),
node->getHtmlCreator());
listOfActiveFormattingElements[i] = newNode;
} else {
listOfActiveFormattingElements[i] = nullptr;
@ -4980,14 +4979,13 @@ nsHtml5TreeBuilder::loadState(nsAHtml5TreeBuilderState* snapshot,
nsHtml5StackNode* node = stackCopy[i];
int32_t listIndex = findInArray(node, listCopy);
if (listIndex == -1) {
nsHtml5StackNode* newNode = createStackNode(
node->getFlags(),
node->ns,
nsHtml5Portability::newLocalFromLocal(node->name, interner),
node->node,
nsHtml5Portability::newLocalFromLocal(node->popName, interner),
nullptr,
node->getHtmlCreator());
nsHtml5StackNode* newNode = createStackNode(node->getFlags(),
node->ns,
node->name,
node->node,
node->popName,
nullptr,
node->getHtmlCreator());
stack[i] = newNode;
} else {
stack[i] = listOfActiveFormattingElements[listIndex];

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

@ -592,9 +592,7 @@ private:
public:
nsAHtml5TreeBuilderState* newSnapshot();
bool snapshotMatches(nsAHtml5TreeBuilderState* snapshot);
void loadState(nsAHtml5TreeBuilderState* snapshot,
nsHtml5AtomTable* interner);
void loadState(nsAHtml5TreeBuilderState* snapshot);
private:
int32_t findInArray(nsHtml5StackNode* node,
jArray<nsHtml5StackNode*, int32_t> arr);

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

@ -278,3 +278,33 @@ def gather_telemetry(command='', success=False, start_time=None, end_time=None,
msg.append(str(error))
print('\n'.join(msg) + '\n' + pprint.pformat(data))
return None
def verify_statedir(statedir):
'''
Verifies the statedir is structured correctly. Returns the outgoing,
submitted and log paths.
Requires presence of the following directories; will raise if absent:
- statedir/telemetry
- statedir/telemetry/outgoing
Creates the following directories and files if absent (first submission):
- statedir/telemetry/submitted
'''
telemetry_dir = os.path.join(statedir, 'telemetry')
outgoing = os.path.join(telemetry_dir, 'outgoing')
submitted = os.path.join(telemetry_dir, 'submitted')
telemetry_log = os.path.join(telemetry_dir, 'telemetry.log')
if not os.path.isdir(telemetry_dir):
raise Exception('{} does not exist'.format(telemetry_dir))
if not os.path.isdir(outgoing):
raise Exception('{} does not exist'.format(outgoing))
if not os.path.isdir(submitted):
os.mkdir(submitted)
return outgoing, submitted, telemetry_log

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

@ -1171,4 +1171,4 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
static const int32_t kUnknownId = -1;
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1550145901574000);
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1550491502080000);

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -69,11 +69,8 @@ function hideAutocompletePopup(jsterm) {
function setJsTermValueForCompletion(jsterm, value) {
// setInputValue does not trigger the autocompletion;
// we need to call `updateAutocompletion` in order to display the popup. And since
// setInputValue sets lastInputValue and updateAutocompletion checks it to trigger
// the autocompletion request, we reset it.
// we need to call `fetchAutocompletionProperties` in order to display the popup.
jsterm.setInputValue(value);
jsterm.lastInputValue = null;
jsterm.updateAutocompletion();
jsterm.fetchAutocompletionProperties();
}

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

@ -43,10 +43,8 @@ module.exports = async function() {
for (const char of Array.from(input)) {
const onPopupOpened = jsterm.autocompletePopup.once("popup-opened");
jsterm.insertStringAtCursor(char);
// We need to remove the lastInputValue set by setInputValue(called by
// insertStringAtCursor), and trigger autocompletion update to show the popup.
jsterm.lastInputValue = null;
jsterm.updateAutocompletion();
// We need to trigger autocompletion update to show the popup.
jsterm.fetchAutocompletionProperties();
await onPopupOpened;
}

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

@ -29,4 +29,5 @@ addEventListener("ImageContentLoaded", function(aEvent) {
// We may not get any responses to Browser:Init if the browser element
// is torn down too quickly.
var outerWindowID = docShell.outerWindowID;
sendAsyncMessage("Browser:Init", {outerWindowID});
var browsingContextId = docShell.browsingContext.id;
sendAsyncMessage("Browser:Init", {outerWindowID, browsingContextId});

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

@ -481,6 +481,18 @@
]]></getter>
</property>
<field name="_browsingContextId">null</field>
<property name="browsingContext" readonly="true">
<getter><![CDATA[
if (!this.isRemoteBrowser) {
return this.docShell.browsingContext;
}
return ChromeUtils.getBrowsingContext(this._browsingContextId);
]]></getter>
</property>
<field name="_lastSearchString">null</field>
@ -1281,6 +1293,7 @@
switch (aMessage.name) {
case "Browser:Init":
this._outerWindowID = data.outerWindowID;
this._browsingContextId = data.browsingContextId;
break;
case "DOMTitleChanged":
this._contentTitle = data.title;

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

@ -139,3 +139,22 @@ add_task(async function test_canonicalJSON_with_deeply_nested_dicts() {
Assert.equal(CanonicalJSON.stringify(records), expected);
});
add_task(async function test_canonicalJSON_should_use_scientific_notation() {
/*
We globally follow the Python float representation, except for exponents < 10
where we drop the leading zero
*/
Assert.equal(CanonicalJSON.stringify(.00099), "0.00099");
Assert.equal(CanonicalJSON.stringify(.000011), "0.000011");
Assert.equal(CanonicalJSON.stringify(.0000011), "0.0000011");
Assert.equal(CanonicalJSON.stringify(.000001), "0.000001");
Assert.equal(CanonicalJSON.stringify(.00000099), "9.9e-7");
Assert.equal(CanonicalJSON.stringify(.0000001), "1e-7");
Assert.equal(CanonicalJSON.stringify(.000000930258908), "9.30258908e-7");
Assert.equal(CanonicalJSON.stringify(.00000000000068272), "6.8272e-13");
Assert.equal(CanonicalJSON.stringify(Math.pow(10, 20)), "100000000000000000000");
Assert.equal(CanonicalJSON.stringify(Math.pow(10, 21)), "1e+21");
Assert.equal(CanonicalJSON.stringify(Math.pow(10, 15) + 0.1), "1000000000000000.1");
Assert.equal(CanonicalJSON.stringify(Math.pow(10, 16) * 1.1), "11000000000000000");
});

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

@ -1711,8 +1711,6 @@ StartRemoteClient(const char* aDesktopStartupID,
client = new XRemoteClient();
}
// There are people who build Wayland without DBus...well
// don't judge others for personal taste.
nsresult rv = client ? client->Init() : NS_ERROR_FAILURE;
if (NS_FAILED(rv))
return REMOTE_NOT_FOUND;