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

This commit is contained in:
Daniel Varga 2019-04-03 09:05:41 +03:00
Родитель 4f5ccd379e c27b25078c
Коммит 14dc5b7d8a
329 изменённых файлов: 5960 добавлений и 2823 удалений

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

@ -1048,7 +1048,7 @@ pref("security.sandbox.gmp.win32k-disable", false);
// of when messaged by the parent after the message loop is running.
pref("security.sandbox.content.mac.earlyinit", true);
// Remove this pref once RDD early init is stable on Release.
pref("security.sandbox.rdd.mac.earlyinit", true);
pref("security.sandbox.rdd.mac.earlyinit", false);
// This pref is discussed in bug 1083344, the naming is inspired from its
// Windows counterpart, but on Mac it's an integer which means:

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

@ -116,9 +116,9 @@ class MozSearchbar extends MozXULElement {
}, { capture: true, once: true });
}
get engines() {
async getEngines() {
if (!this._engines)
this._engines = Services.search.getVisibleEngines();
this._engines = await Services.search.getVisibleEngines();
return this._engines;
}
@ -207,18 +207,32 @@ class MozSearchbar extends MozXULElement {
}
}
selectEngine(aEvent, isNextEngine) {
// Find the new index
let newIndex = this.engines.indexOf(this.currentEngine);
newIndex += isNextEngine ? 1 : -1;
if (newIndex >= 0 && newIndex < this.engines.length) {
this.currentEngine = this.engines[newIndex];
}
async selectEngine(aEvent, isNextEngine) {
// Stop event bubbling now, because the rest of this method is async.
aEvent.preventDefault();
aEvent.stopPropagation();
// Find the new index.
let engines = await this.getEngines();
let currentName = this.currentEngine.name;
let newIndex = -1;
let lastIndex = engines.length - 1;
for (let i = lastIndex; i >= 0; --i) {
if (engines[i].name == currentName) {
// Check bounds to cycle through the list of engines continuously.
if (!isNextEngine && i == 0) {
newIndex = lastIndex;
} else if (isNextEngine && i == lastIndex) {
newIndex = 0;
} else {
newIndex = i + (isNextEngine ? 1 : -1);
}
break;
}
}
this.currentEngine = engines[newIndex];
this.openSuggestionsPanel();
}

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

@ -1,5 +1,6 @@
// Tests that keyboard navigation in the search panel works as designed.
const {SearchTestUtils} = ChromeUtils.import("resource://testing-common/SearchTestUtils.jsm");
const searchPopup = document.getElementById("PopupSearchAutoComplete");
const oneOffsContainer = searchPopup.searchOneOffsContainer;
@ -306,6 +307,50 @@ add_task(async function test_alt_up() {
ok(!textbox.selectedButton, "no one-off should be selected anymore");
});
add_task(async function test_accel_down() {
// Pressing accel+down should select the next visible search engine, without
// selecting suggestions.
let engines = await Services.search.getVisibleEngines();
let current = Services.search.defaultEngine;
let currIdx = -1;
for (let i = 0, l = engines.length; i < l; ++i) {
if (engines[i].name == current.name) {
currIdx = i;
break;
}
}
for (let i = 0, l = engines.length; i < l; ++i) {
EventUtils.synthesizeKey("KEY_ArrowDown", {accelKey: true});
await SearchTestUtils.promiseSearchNotification("engine-default", "browser-search-engine-modified");
let expected = engines[++currIdx % engines.length];
is(Services.search.defaultEngine.name, expected.name, "Default engine should have changed");
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
}
Services.search.defaultEngine = current;
});
add_task(async function test_accel_up() {
// Pressing accel+down should select the previous visible search engine, without
// selecting suggestions.
let engines = await Services.search.getVisibleEngines();
let current = Services.search.defaultEngine;
let currIdx = -1;
for (let i = 0, l = engines.length; i < l; ++i) {
if (engines[i].name == current.name) {
currIdx = i;
break;
}
}
for (let i = 0, l = engines.length; i < l; ++i) {
EventUtils.synthesizeKey("KEY_ArrowUp", {accelKey: true});
await SearchTestUtils.promiseSearchNotification("engine-default", "browser-search-engine-modified");
let expected = engines[--currIdx < 0 ? currIdx = engines.length - 1 : currIdx];
is(Services.search.defaultEngine.name, expected.name, "Default engine should have changed");
is(searchPopup.selectedIndex, -1, "no suggestion should be selected");
}
Services.search.defaultEngine = current;
});
add_task(async function test_tab_and_arrows() {
// Check the initial state is as expected.
ok(!textbox.selectedButton, "no one-off button should be selected");

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

@ -3818,8 +3818,14 @@ var SessionStoreInternal = {
});
let sc = Services.io.QueryInterface(Ci.nsISpeculativeConnect);
let uri = Services.io.newURI(url);
sc.speculativeConnect(uri, principal, null);
return true;
try {
sc.speculativeConnect(uri, principal, null);
return true;
} catch (error) {
// Can't setup speculative connection for this url.
Cu.reportError(error);
return false;
}
}
return false;
},

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

@ -27,5 +27,6 @@ module.exports = {
requireReturn: false,
requireReturnDescription: false,
}],
"no-unused-expressions": "error",
}
};

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

@ -159,7 +159,8 @@ class UrlbarInput {
this._initPasteAndGo();
// Tracks IME composition.
this._compositionState == UrlbarUtils.COMPOSITION.NONE;
this._compositionState = UrlbarUtils.COMPOSITION.NONE;
this._compositionClosedPopup = false;
}
/**
@ -206,6 +207,11 @@ class UrlbarInput {
this.valueFormatter.update();
}
/**
* This exists for legacy compatibility, and can be removed once the old
* urlbar code goes away, by changing callers. Internal consumers should use
* view.close().
*/
closePopup() {
this.view.close();
}
@ -1052,7 +1058,7 @@ class UrlbarInput {
// Ensure the start of the URL is visible for usability reasons.
this.selectionStart = this.selectionEnd = 0;
this.closePopup();
this.view.close();
}
/**
@ -1212,6 +1218,15 @@ class UrlbarInput {
this._untrimmedValue = value;
this.window.gBrowser.userTypedValue = value;
let compositionState = this._compositionState;
let compositionClosedPopup = this._compositionClosedPopup;
// Clear composition values if we're no more composing.
if (this._compositionState != UrlbarUtils.COMPOSITION.COMPOSING) {
this._compositionState = UrlbarUtils.COMPOSITION.NONE;
this._compositionClosedPopup = false;
}
if (value) {
this.setAttribute("usertyping", "true");
} else {
@ -1232,17 +1247,14 @@ class UrlbarInput {
// 3. a compositionend event
// 4. an input event
// We should do nothing during composition.
if (this._compositionState == UrlbarUtils.COMPOSITION.COMPOSING) {
// We should do nothing during composition or if composition was canceled
// and we didn't close the popup on composition start.
if (compositionState == UrlbarUtils.COMPOSITION.COMPOSING ||
(compositionState == UrlbarUtils.COMPOSITION.CANCELED &&
!compositionClosedPopup)) {
return;
}
let handlingCompositionCommit =
this._compositionState == UrlbarUtils.COMPOSITION.COMMIT;
if (handlingCompositionCommit) {
this._compositionState = UrlbarUtils.COMPOSITION.NONE;
}
let sameSearchStrings = value == this._lastSearchString;
// TODO (bug 1524550): Properly detect autofill removal, rather than
@ -1253,11 +1265,11 @@ class UrlbarInput {
this._autofillPlaceholder.startsWith(value);
// Don't search again when the new search would produce the same results.
// If we're handling a composition commit, we must continue the search
// If we're handling a composition input, we must continue the search
// because we canceled the previous search on composition start.
if (sameSearchStrings &&
!deletedAutofilledSubstring &&
!handlingCompositionCommit &&
compositionState == UrlbarUtils.COMPOSITION.NONE &&
value.length > 0) {
return;
}
@ -1376,7 +1388,12 @@ class UrlbarInput {
this._compositionState = UrlbarUtils.COMPOSITION.COMPOSING;
// Close the view. This will also stop searching.
this.closePopup();
if (this.view.isOpen) {
this._compositionClosedPopup = true;
this.view.close();
} else {
this._compositionClosedPopup = false;
}
}
_on_compositionend(event) {
@ -1386,7 +1403,8 @@ class UrlbarInput {
// We can't yet retrieve the committed value from the editor, since it isn't
// completely committed yet. We'll handle it at the next input event.
this._compositionState = UrlbarUtils.COMPOSITION.COMMIT;
this._compositionState = event.data ? UrlbarUtils.COMPOSITION.COMMIT :
UrlbarUtils.COMPOSITION.CANCELED;
}
_on_popupshowing() {

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

@ -115,6 +115,7 @@ var UrlbarUtils = {
NONE: 1,
COMPOSING: 2,
COMMIT: 3,
CANCELED: 4,
},
// This defines possible reasons for canceling a query.

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

@ -341,12 +341,6 @@ class UrlbarView {
this.panel.removeAttribute("hidden");
this.panel.removeAttribute("actionoverride");
this._alignPanel();
this.panel.openPopup(this.input.textbox, "after_start");
}
_alignPanel() {
// Make the panel span the width of the window.
let documentRect =
this._getBoundsWithoutFlushing(this.document.documentElement);
@ -394,10 +388,12 @@ class UrlbarView {
// Align the panel with the input's parent toolbar.
let toolbarRect =
this._getBoundsWithoutFlushing(this.input.textbox.closest("toolbar"));
this.panel.style.marginInlineStart = this.window.RTL_UI ?
inputRect.right - documentRect.right + "px" :
documentRect.left - inputRect.left + "px";
this.panel.style.marginTop = inputRect.top - toolbarRect.top + "px";
let offsetX = Math.round(this.window.RTL_UI ?
inputRect.right - documentRect.right :
documentRect.left - inputRect.left);
let offsetY = Math.round(inputRect.top - toolbarRect.top);
this.panel.openPopup(this.input.textbox, "after_start", offsetX, offsetY);
}
_createRow() {

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

@ -34,6 +34,7 @@ skip-if = os != "mac" # Mac only feature
[browser_caret_navigation.js]
[browser_dragdropURL.js]
[browser_dropmarker.js]
[browser_ime_composition.js]
[browser_keepStateAcrossTabSwitches.js]
[browser_keyword_override.js]
[browser_keyword_select_and_type.js]

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

@ -0,0 +1,176 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests ime composition handling.
function synthesizeCompositionChange(string) {
EventUtils.synthesizeCompositionChange({
composition: {
string,
clauses: [
{ length: string.length, attr: Ci.nsITextInputProcessor.ATTR_RAW_CLAUSE },
],
},
caret: { start: string.length, length: 0 },
key: { key: string ? string[string.length - 1] : "KEY_Backspace" },
});
// Modifying composition should not open the popup.
Assert.ok(!UrlbarTestUtils.isPopupOpen(window), "Popup should be closed");
}
add_task(async function test_composition() {
gURLBar.focus();
// Add at least one typed entry for the empty results set. Also clear history
// so that this can be over the autofill threshold.
await PlacesUtils.history.clear();
await PlacesTestUtils.addVisits({
uri: "http://mozilla.org/",
transition: PlacesUtils.history.TRANSITIONS.TYPED,
});
info("The popup should not be shown during composition but, after compositionend, it should be.");
Assert.ok(!UrlbarTestUtils.isPopupOpen(window), "Popup should be closed");
synthesizeCompositionChange("I");
Assert.equal(gURLBar.value, "I", "Check urlbar value");
synthesizeCompositionChange("In");
Assert.equal(gURLBar.value, "In", "Check urlbar value");
// Committing composition should open the popup.
await UrlbarTestUtils.promisePopupOpen(window, () => {
EventUtils.synthesizeComposition({
type: "compositioncommitasis",
key: { key: "KEY_Enter" },
});
});
Assert.equal(gURLBar.value, "In", "Check urlbar value");
info("If composition starts while the popup is shown, the compositionstart event should close the popup.");
Assert.ok(UrlbarTestUtils.isPopupOpen(window), "Popup should be open");
synthesizeCompositionChange("t");
Assert.equal(gURLBar.value, "Int", "Check urlbar value");
synthesizeCompositionChange("te");
Assert.equal(gURLBar.value, "Inte", "Check urlbar value");
// Committing composition should open the popup.
await UrlbarTestUtils.promisePopupOpen(window, () => {
EventUtils.synthesizeComposition({
type: "compositioncommitasis",
key: { key: "KEY_Enter" },
});
});
Assert.equal(gURLBar.value, "Inte", "Check urlbar value");
info("If composition is cancelled, the value shouldn't be changed.");
Assert.ok(UrlbarTestUtils.isPopupOpen(window), "Popup should be open");
synthesizeCompositionChange("r");
Assert.equal(gURLBar.value, "Inter", "Check urlbar value");
synthesizeCompositionChange("");
Assert.equal(gURLBar.value, "Inte", "Check urlbar value");
// Canceled compositionend should reopen the popup.
await UrlbarTestUtils.promisePopupOpen(window, () => {
EventUtils.synthesizeComposition({
type: "compositioncommit",
data: "",
key: { key: "KEY_Escape" },
});
});
Assert.equal(gURLBar.value, "Inte", "Check urlbar value");
info("If composition replaces some characters and canceled, the search string should be the latest value.");
Assert.ok(UrlbarTestUtils.isPopupOpen(window), "Popup should be open");
EventUtils.synthesizeKey("VK_LEFT", { shiftKey: true });
EventUtils.synthesizeKey("VK_LEFT", { shiftKey: true });
synthesizeCompositionChange("t");
Assert.equal(gURLBar.value, "Int", "Check urlbar value");
synthesizeCompositionChange("te");
Assert.equal(gURLBar.value, "Inte", "Check urlbar value");
synthesizeCompositionChange("");
Assert.equal(gURLBar.value, "In", "Check urlbar value");
// Canceled compositionend should search the result with the latest value.
await UrlbarTestUtils.promisePopupOpen(window, () => {
EventUtils.synthesizeComposition({
type: "compositioncommitasis",
key: { key: "KEY_Escape" },
});
});
Assert.equal(gURLBar.value, "In", "Check urlbar value");
info("If all characters are removed, the popup should be closed.");
Assert.ok(UrlbarTestUtils.isPopupOpen(window), "Popup should be open");
await UrlbarTestUtils.promisePopupClose(window, () => {
EventUtils.synthesizeKey("KEY_Backspace", {});
EventUtils.synthesizeKey("KEY_Backspace", {});
});
Assert.equal(gURLBar.value, "", "Check urlbar value");
info("Composition which is canceled shouldn't cause opening the popup.");
Assert.ok(!UrlbarTestUtils.isPopupOpen(window), "Popup should be closed");
synthesizeCompositionChange("I");
Assert.equal(gURLBar.value, "I", "Check urlbar value");
synthesizeCompositionChange("In");
Assert.equal(gURLBar.value, "In", "Check urlbar value");
synthesizeCompositionChange("");
Assert.equal(gURLBar.value, "", "Check urlbar value");
// Canceled compositionend shouldn't open the popup if it was closed.
EventUtils.synthesizeComposition({
type: "compositioncommitasis",
key: { key: "KEY_Escape" },
});
Assert.ok(!UrlbarTestUtils.isPopupOpen(window), "Popup should be closed");
Assert.equal(gURLBar.value, "", "Check urlbar value");
info("Down key should open the popup even if the editor is empty.");
await UrlbarTestUtils.promisePopupOpen(window, () => {
EventUtils.synthesizeKey("KEY_ArrowDown", {});
});
Assert.equal(gURLBar.value, "", "Check urlbar value");
info("If popup is open at starting composition, the popup should be reopened after composition anyway.");
Assert.ok(UrlbarTestUtils.isPopupOpen(window), "Popup should be open");
synthesizeCompositionChange("I");
Assert.equal(gURLBar.value, "I", "Check urlbar value");
synthesizeCompositionChange("In");
Assert.equal(gURLBar.value, "In", "Check urlbar value");
synthesizeCompositionChange("");
Assert.equal(gURLBar.value, "", "Check urlbar value");
// A canceled compositionend should open the popup if it was open.
await UrlbarTestUtils.promisePopupOpen(window, () => {
EventUtils.synthesizeComposition({
type: "compositioncommitasis",
key: { key: "KEY_Escape" },
});
});
Assert.equal(gURLBar.value, "", "Check urlbar value");
info("Type normally, and hit escape, the popup should be closed.");
Assert.ok(UrlbarTestUtils.isPopupOpen(window), "Popup should be open");
EventUtils.synthesizeKey("I", {});
EventUtils.synthesizeKey("n", {});
// The old urlbar may close/reopen the popup and then ESC wouldn't act as
// expected.
if (!UrlbarPrefs.get("quantumbar")) {
await UrlbarTestUtils.promiseSearchComplete(window);
}
await UrlbarTestUtils.promisePopupClose(window, () => {
EventUtils.synthesizeKey("KEY_Escape", {});
});
Assert.equal(gURLBar.value, "In", "Check urlbar value");
// Clear typed chars.
EventUtils.synthesizeKey("KEY_Backspace", {});
EventUtils.synthesizeKey("KEY_Backspace", {});
Assert.equal(gURLBar.value, "", "Check urlbar value");
info("With autofill, compositionstart shouldn't open the popup");
Assert.ok(!UrlbarTestUtils.isPopupOpen(window), "Popup should be closed");
synthesizeCompositionChange("M");
Assert.equal(gURLBar.value, "M", "Check urlbar value");
synthesizeCompositionChange("Mo");
Assert.equal(gURLBar.value, "Mo", "Check urlbar value");
// Committing composition should open the popup.
await UrlbarTestUtils.promisePopupOpen(window, () => {
EventUtils.synthesizeComposition({
type: "compositioncommitasis",
key: { key: "KEY_Enter" },
});
});
Assert.equal(gURLBar.value, "Mozilla.org/", "Check urlbar value");
});

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

@ -54,6 +54,7 @@ skip-if = os != "mac" # Mac only feature
[../browser/browser_autocomplete_tag_star_visibility.js]
[../browser/browser_canonizeURL.js]
[../browser/browser_dragdropURL.js]
[../browser/browser_ime_composition.js]
[../browser/browser_keepStateAcrossTabSwitches.js]
[../browser/browser_keyword_override.js]
[../browser/browser_keyword_select_and_type.js]

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

@ -60,13 +60,13 @@
too long, but they actually work just fine, the warning is spurious. -->
<CustomAction Id="RunInstallNoDir" Return="check" Execute="deferred"
HideTarget="no" Impersonate="no" BinaryKey="WrappedExe"
ExeCommand="/S /TaskbarShortcut=[TASKBAR_SHORTCUT] /DesktopShortcut=[DESKTOP_SHORTCUT] /StartMenuShortcut=[START_MENU_SHORTCUT] /MaintenanceService=[INSTALL_MAINTENANCE_SERVICE] /RemoveDistributionDir=[REMOTE_DISTRIBUTION_DIR] /PreventRebootRequired=[PREVENT_REBOOT_REQUIRED] /OptionalExtensions=[OPTIONAL_EXTENSIONS] /LaunchedFromMSI" />
ExeCommand="/S /TaskbarShortcut=[TASKBAR_SHORTCUT] /DesktopShortcut=[DESKTOP_SHORTCUT] /StartMenuShortcut=[START_MENU_SHORTCUT] /MaintenanceService=[INSTALL_MAINTENANCE_SERVICE] /RemoveDistributionDir=[REMOVE_DISTRIBUTION_DIR] /PreventRebootRequired=[PREVENT_REBOOT_REQUIRED] /OptionalExtensions=[OPTIONAL_EXTENSIONS] /LaunchedFromMSI" />
<CustomAction Id="RunInstallDirPath" Return="check" Execute="deferred"
HideTarget="no" Impersonate="no" BinaryKey="WrappedExe"
ExeCommand="/S /InstallDirectoryPath=[INSTALL_DIRECTORY_PATH] /TaskbarShortcut=[TASKBAR_SHORTCUT] /DesktopShortcut=[DESKTOP_SHORTCUT] /StartMenuShortcut=[START_MENU_SHORTCUT] /MaintenanceService=[INSTALL_MAINTENANCE_SERVICE] /RemoveDistributionDir=[REMOTE_DISTRIBUTION_DIR] /PreventRebootRequired=[PREVENT_REBOOT_REQUIRED] /OptionalExtensions=[OPTIONAL_EXTENSIONS] /LaunchedFromMSI" />
ExeCommand="/S /InstallDirectoryPath=[INSTALL_DIRECTORY_PATH] /TaskbarShortcut=[TASKBAR_SHORTCUT] /DesktopShortcut=[DESKTOP_SHORTCUT] /StartMenuShortcut=[START_MENU_SHORTCUT] /MaintenanceService=[INSTALL_MAINTENANCE_SERVICE] /RemoveDistributionDir=[REMOVE_DISTRIBUTION_DIR] /PreventRebootRequired=[PREVENT_REBOOT_REQUIRED] /OptionalExtensions=[OPTIONAL_EXTENSIONS] /LaunchedFromMSI" />
<CustomAction Id="RunInstallDirName" Return="check" Execute="deferred"
HideTarget="no" Impersonate="no" BinaryKey="WrappedExe"
ExeCommand="/S /InstallDirectoryName=[INSTALL_DIRECTORY_NAME] /TaskbarShortcut=[TASKBAR_SHORTCUT] /DesktopShortcut=[DESKTOP_SHORTCUT] /StartMenuShortcut=[START_MENU_SHORTCUT] /MaintenanceService=[INSTALL_MAINTENANCE_SERVICE] /RemoveDistributionDir=[REMOTE_DISTRIBUTION_DIR] /PreventRebootRequired=[PREVENT_REBOOT_REQUIRED] /OptionalExtensions=[OPTIONAL_EXTENSIONS] /LaunchedFromMSI" />
ExeCommand="/S /InstallDirectoryName=[INSTALL_DIRECTORY_NAME] /TaskbarShortcut=[TASKBAR_SHORTCUT] /DesktopShortcut=[DESKTOP_SHORTCUT] /StartMenuShortcut=[START_MENU_SHORTCUT] /MaintenanceService=[INSTALL_MAINTENANCE_SERVICE] /RemoveDistributionDir=[REMOVE_DISTRIBUTION_DIR] /PreventRebootRequired=[PREVENT_REBOOT_REQUIRED] /OptionalExtensions=[OPTIONAL_EXTENSIONS] /LaunchedFromMSI" />
<CustomAction Id="RunExtractOnly" Return="check" Execute="deferred"
HideTarget="no" Impersonate="no" BinaryKey="WrappedExe"
ExeCommand="/ExtractDir=[EXTRACT_DIR]" />

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

@ -339,7 +339,8 @@ html|input.urlbar-input {
* bottom of the nav bar, OSX calculates the panel position with an missing
* 1px - https://bugzilla.mozilla.org/show_bug.cgi?id=1406353
*/
#PopupAutoCompleteRichResult {
#PopupAutoCompleteRichResult,
#urlbar-results {
margin-top: 1px;
}

3
config/external/nspr/pr/moz.build поставляемый
Просмотреть файл

@ -40,6 +40,9 @@ elif CONFIG['OS_TARGET'] in ('FreeBSD', 'OpenBSD', 'NetBSD'):
SOURCES += ['/nsprpub/pr/src/md/unix/%s.c' % CONFIG['OS_TARGET'].lower()]
elif CONFIG['OS_TARGET'] == 'Darwin':
OS_LIBS += ['-framework CoreServices']
# See also IncreaseDescriptorLimits in toolkit/xre/nsAppRunner.cpp
DEFINES['FD_SETSIZE'] = 4096
DEFINES['_DARWIN_UNLIMITED_SELECT'] = True
if not CONFIG['HOST_MAJOR_VERSION']:
DEFINES.update(
HAS_CONNECTX=True,

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

@ -15,7 +15,7 @@
"byName": {},
"byBlocks": {},
"usedIds": {
"1": 1
"0": 0
}
}
}
@ -36,7 +36,7 @@
"byName": {},
"byBlocks": {},
"usedIds": {
"1": 1
"0": 0
}
}
}
@ -57,7 +57,7 @@
"byName": {},
"byBlocks": {},
"usedIds": {
"1": 1
"0": 0
}
}
}
@ -78,7 +78,7 @@
"byName": {},
"byBlocks": {},
"usedIds": {
"1": 1
"0": 0
}
}
}
@ -99,7 +99,7 @@
"byName": {},
"byBlocks": {},
"usedIds": {
"1": 1
"0": 0
}
}
}
@ -120,7 +120,7 @@
"byName": {},
"byBlocks": {},
"usedIds": {
"1": 1
"0": 0
}
}
}
@ -141,7 +141,7 @@
"byName": {},
"byBlocks": {},
"usedIds": {
"1": 1
"0": 0
}
}
}

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

@ -43,14 +43,20 @@
src="chrome://devtools/content/shared/theme-switching.js"
></script>
<script type="text/javascript">
const { BrowserLoader } = ChromeUtils.import(
"resource://devtools/client/shared/browser-loader.js"
);
const { require } = BrowserLoader({
baseURI: "resource://devtools/client/debugger/new",
window
});
Debugger = require("devtools/client/debugger/new/src/main");
try {
const { BrowserLoader } = ChromeUtils.import(
"resource://devtools/client/shared/browser-loader.js"
);
const { require } = BrowserLoader({
baseURI: "resource://devtools/client/debugger/new",
window
});
Debugger = require("devtools/client/debugger/new/src/main");
} catch (e) {
dump("Exception happened while loading the debugger:\n");
dump(e + "\n");
dump(e.stack + "\n");
}
</script>
</body>
</html>

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

@ -6,8 +6,12 @@
const md5 = require("md5");
function originalToGeneratedId(originalId: string) {
const match = originalId.match(/(.*)\/originalSource/);
function originalToGeneratedId(sourceId: string) {
if (isGeneratedId(sourceId)) {
return sourceId;
}
const match = sourceId.match(/(.*)\/originalSource/);
return match ? match[1] : "";
}

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

@ -10,16 +10,25 @@ import { uniqBy, zip } from "lodash";
import {
getSource,
getSourceFromId,
getGeneratedSourceById,
hasBreakpointPositions,
getBreakpointPositionsForSource
} from "../../selectors";
import type { MappedLocation, SourceLocation } from "../../types";
import type { ThunkArgs } from "../../actions/types";
import type {
MappedLocation,
SourceLocation,
BreakpointPositions
} from "../../types";
import { makeBreakpointId } from "../../utils/breakpoint";
import {
memoizeableAction,
type MemoizedAction
} from "../../utils/memoizableAction";
import typeof SourceMaps from "../../../packages/devtools-source-map/src";
const requests = new Map();
// const requests = new Map();
async function mapLocations(
generatedLocations: SourceLocation[],
@ -113,55 +122,29 @@ async function _setBreakpointPositions(sourceId, thunkArgs) {
if (!source) {
return;
}
dispatch({
type: "ADD_BREAKPOINT_POSITIONS",
source: source,
positions
});
return positions;
}
function buildCacheKey(sourceId: string, thunkArgs: ThunkArgs): string {
const generatedSource = getSource(
thunkArgs.getState(),
isOriginalId(sourceId) ? originalToGeneratedId(sourceId) : sourceId
);
let key = sourceId;
if (generatedSource) {
for (const actor of generatedSource.actors) {
key += `:${actor.actor}`;
}
}
return key;
}
export function setBreakpointPositions(sourceId: string) {
return async (thunkArgs: ThunkArgs) => {
const { getState } = thunkArgs;
if (hasBreakpointPositions(getState(), sourceId)) {
return getBreakpointPositionsForSource(getState(), sourceId);
}
const cacheKey = buildCacheKey(sourceId, thunkArgs);
if (!requests.has(cacheKey)) {
requests.set(
cacheKey,
(async () => {
try {
await _setBreakpointPositions(sourceId, thunkArgs);
} catch (e) {
// TODO: Address exceptions originating from 1536618
// `Debugger.Source belongs to a different Debugger`
} finally {
requests.delete(cacheKey);
}
})()
);
}
await requests.get(cacheKey);
return getBreakpointPositionsForSource(getState(), sourceId);
};
}
export const setBreakpointPositions: MemoizedAction<
{ sourceId: string },
?BreakpointPositions
> = memoizeableAction("setBreakpointPositions", {
hasValue: ({ sourceId }, { getState }) =>
hasBreakpointPositions(getState(), sourceId),
getValue: ({ sourceId }, { getState }) =>
getBreakpointPositionsForSource(getState(), sourceId),
createKey({ sourceId }, { getState }) {
const generatedSource = getGeneratedSourceById(getState(), sourceId);
const actors = generatedSource.actors.map(({ actor }) => actor);
return [sourceId, ...actors].join(":");
},
action: ({ sourceId }, thunkArgs) =>
_setBreakpointPositions(sourceId, thunkArgs)
});

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

@ -4,13 +4,6 @@
// @flow
import type { ThunkArgs } from "../types";
import type {
Breakpoint,
BreakpointOptions,
SourceLocation
} from "../../types";
import {
makeBreakpointLocation,
makeBreakpointId,
@ -23,15 +16,22 @@ import {
getBreakpoint,
getBreakpointPositionsForLocation,
getFirstBreakpointPosition,
getSourceFromId,
getSymbols
} from "../../selectors";
import { loadSourceText } from "../sources/loadSourceText";
import { loadSourceById } from "../sources/loadSourceText";
import { setBreakpointPositions } from "./breakpointPositions";
import { recordEvent } from "../../utils/telemetry";
import type { ThunkArgs } from "../types";
import type {
Breakpoint,
BreakpointOptions,
BreakpointPosition,
SourceLocation
} from "../../types";
// This file has the primitive operations used to modify individual breakpoints
// and keep them in sync with the breakpoints installed on server threads. These
// are collected here to make it easier to preserve the following invariant:
@ -102,9 +102,9 @@ export function addBreakpoint(
const { sourceId, column } = initialLocation;
await dispatch(setBreakpointPositions(sourceId));
await dispatch(setBreakpointPositions({ sourceId }));
const position = column
const position: ?BreakpointPosition = column
? getBreakpointPositionsForLocation(getState(), initialLocation)
: getFirstBreakpointPosition(getState(), initialLocation);
@ -113,20 +113,12 @@ export function addBreakpoint(
}
const { location, generatedLocation } = position;
// Both the original and generated sources must be loaded to get the
// breakpoint's text.
await dispatch(
loadSourceText(getSourceFromId(getState(), location.sourceId))
);
await dispatch(
loadSourceText(getSourceFromId(getState(), generatedLocation.sourceId))
);
const source = getSourceFromId(getState(), location.sourceId);
const generatedSource = getSourceFromId(
getState(),
generatedLocation.sourceId
const source = await dispatch(loadSourceById(sourceId));
const generatedSource = await dispatch(
loadSourceById(generatedLocation.sourceId)
);
const symbols = getSymbols(getState(), source);
@ -156,16 +148,10 @@ export function addBreakpoint(
// at |generatedLocation|.
const generatedId = makeBreakpointId(breakpoint.generatedLocation);
if (id != generatedId && getBreakpoint(getState(), generatedLocation)) {
dispatch({
type: "REMOVE_BREAKPOINT",
location: generatedLocation
});
dispatch({ type: "REMOVE_BREAKPOINT", location: generatedLocation });
}
dispatch({
type: "SET_BREAKPOINT",
breakpoint
});
dispatch({ type: "SET_BREAKPOINT", breakpoint });
if (disabled) {
// If we just clobbered an enabled breakpoint with a disabled one, we need

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

@ -5,6 +5,7 @@
// @flow
import { setBreakpointPositions } from "./breakpointPositions";
import { setSymbols } from "../sources/symbols";
import {
assertPendingBreakpoint,
findFunctionByName,
@ -19,19 +20,24 @@ import { getSource, getBreakpoint } from "../../selectors";
import { removeBreakpoint, addBreakpoint } from ".";
import type { ThunkArgs } from "../types";
import type { LoadedSymbols } from "../../reducers/types";
import type {
SourceLocation,
ASTLocation,
PendingBreakpoint,
SourceId
SourceId,
BreakpointPositions
} from "../../types";
async function findBreakpointPosition(
{ getState, dispatch },
location: SourceLocation
) {
const positions = await dispatch(setBreakpointPositions(location.sourceId));
const positions: BreakpointPositions = await dispatch(
setBreakpointPositions({ sourceId: location.sourceId })
);
const position = findPosition(positions, location);
return position && position.generatedLocation;
}
@ -39,9 +45,13 @@ async function findBreakpointPosition(
async function findNewLocation(
{ name, offset, index }: ASTLocation,
location: SourceLocation,
source
source,
thunkArgs
) {
const func = await findFunctionByName(source, name, index);
const symbols: LoadedSymbols = await thunkArgs.dispatch(
setSymbols({ source })
);
const func = findFunctionByName(symbols, name, index);
// Fallback onto the location line, if we do not find a function is not found
let line = location.line;
@ -133,7 +143,8 @@ export function syncBreakpoint(
const newLocation = await findNewLocation(
astLocation,
previousLocation,
source
source,
thunkArgs
);
const newGeneratedLocation = await findBreakpointPosition(

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

@ -21,7 +21,7 @@ describe("breakpointPositions", () => {
const { dispatch, getState } = store;
await dispatch(actions.newSource(makeSource("foo")));
dispatch(actions.setBreakpointPositions("foo"));
dispatch(actions.setBreakpointPositions({ sourceId: "foo" }));
await waitForState(store, state =>
selectors.hasBreakpointPositions(state, "foo")
@ -61,8 +61,8 @@ describe("breakpointPositions", () => {
const { dispatch, getState } = store;
await dispatch(actions.newSource(makeSource("foo")));
dispatch(actions.setBreakpointPositions("foo"));
dispatch(actions.setBreakpointPositions("foo"));
dispatch(actions.setBreakpointPositions({ sourceId: "foo" }));
dispatch(actions.setBreakpointPositions({ sourceId: "foo" }));
resolve({ "9": [1] });
await waitForState(store, state =>

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

@ -33,7 +33,7 @@ describe("breakpoints", () => {
const source = makeSource("a");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(
actions.setSelectedLocation(source, {
line: 1,
@ -63,7 +63,7 @@ describe("breakpoints", () => {
};
const source = makeSource("a");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(
actions.setSelectedLocation(source, {
line: 1,
@ -90,7 +90,7 @@ describe("breakpoints", () => {
};
const source = makeSource("a");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(
actions.setSelectedLocation(source, {
line: 1,
@ -124,7 +124,7 @@ describe("breakpoints", () => {
const source = makeSource("a");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(
actions.setSelectedLocation(source, {
line: 1,
@ -163,11 +163,11 @@ describe("breakpoints", () => {
const aSource = makeSource("a");
await dispatch(actions.newSource(aSource));
await dispatch(actions.loadSourceText(aSource));
await dispatch(actions.loadSourceText({ source: aSource }));
const bSource = makeSource("b");
await dispatch(actions.newSource(bSource));
await dispatch(actions.loadSourceText(bSource));
await dispatch(actions.loadSourceText({ source: bSource }));
await dispatch(
actions.setSelectedLocation(aSource, {
@ -210,11 +210,11 @@ describe("breakpoints", () => {
const aSource = makeSource("a");
await dispatch(actions.newSource(aSource));
await dispatch(actions.loadSourceText(aSource));
await dispatch(actions.loadSourceText({ source: aSource }));
const bSource = makeSource("b");
await dispatch(actions.newSource(bSource));
await dispatch(actions.loadSourceText(bSource));
await dispatch(actions.loadSourceText({ source: bSource }));
await dispatch(actions.addBreakpoint(loc1));
await dispatch(actions.addBreakpoint(loc2));
@ -243,7 +243,7 @@ describe("breakpoints", () => {
const aSource = makeSource("a");
await dispatch(actions.newSource(aSource));
await dispatch(actions.loadSourceText(aSource));
await dispatch(actions.loadSourceText({ source: aSource }));
await dispatch(actions.addBreakpoint(loc));
let bp = selectors.getBreakpoint(getState(), loc);
@ -287,11 +287,11 @@ describe("breakpoints", () => {
const aSource = makeSource("a");
await dispatch(actions.newSource(aSource));
await dispatch(actions.loadSourceText(aSource));
await dispatch(actions.loadSourceText({ source: aSource }));
const bSource = makeSource("b");
await dispatch(actions.newSource(bSource));
await dispatch(actions.loadSourceText(bSource));
await dispatch(actions.loadSourceText({ source: bSource }));
await dispatch(actions.addBreakpoint(loc1));
await dispatch(actions.addBreakpoint(loc2));
@ -320,7 +320,7 @@ describe("breakpoints", () => {
const source = makeSource("foo1");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.selectLocation(loc));
@ -340,7 +340,7 @@ describe("breakpoints", () => {
const source = makeSource("foo1");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.selectLocation({ sourceId: "foo1", line: 1 }));
@ -368,7 +368,7 @@ describe("breakpoints", () => {
const source = makeSource("a");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.addBreakpoint(loc));
@ -398,7 +398,7 @@ describe("breakpoints", () => {
const source = makeSource("a");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.addBreakpoint(loc));
let bp = selectors.getBreakpoint(getState(), loc);
@ -436,7 +436,7 @@ describe("breakpoints", () => {
const source = makeSource("a.js");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.addBreakpoint(loc));
await dispatch(actions.togglePrettyPrint("a.js"));

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

@ -8,11 +8,13 @@ import {
getFrames,
getSymbols,
getSource,
getSourceFromId,
getSelectedFrame
} from "../../selectors";
import assert from "../../utils/assert";
import { findClosestFunction } from "../../utils/ast";
import { setSymbols } from "../sources/symbols";
import type { Frame, ThreadId } from "../../types";
import type { State } from "../../reducers/types";
@ -67,6 +69,7 @@ export function mapDisplayNames(
if (frame.isOriginal) {
return frame;
}
const source = getSource(getState(), frame.location.sourceId);
if (!source) {
@ -152,6 +155,15 @@ async function expandFrames(
return result;
}
async function updateFrameSymbols(frames, { dispatch, getState }) {
await Promise.all(
frames.map(frame => {
const source = getSourceFromId(getState(), frame.location.sourceId);
return dispatch(setSymbols({ source }));
})
);
}
/**
* Map call stack frame locations and display names to originals.
* e.g.
@ -162,13 +174,16 @@ async function expandFrames(
* @static
*/
export function mapFrames(thread: ThreadId) {
return async function({ dispatch, getState, sourceMaps }: ThunkArgs) {
return async function(thunkArgs: ThunkArgs) {
const { dispatch, getState, sourceMaps } = thunkArgs;
const frames = getFrames(getState(), thread);
if (!frames) {
return;
}
let mappedFrames = await updateFrameLocations(frames, sourceMaps);
await updateFrameSymbols(mappedFrames, thunkArgs);
mappedFrames = await expandFrames(mappedFrames, sourceMaps, getState);
mappedFrames = mapDisplayNames(mappedFrames, getState);

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

@ -72,9 +72,9 @@ export function mapScopes(scopes: Promise<Scope>, frame: Frame) {
return null;
}
await dispatch(loadSourceText(source));
await dispatch(loadSourceText({ source }));
if (isOriginal(source)) {
await dispatch(loadSourceText(generatedSource));
await dispatch(loadSourceText({ source: generatedSource }));
}
try {

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

@ -161,7 +161,6 @@ describe("pause", () => {
const source = makeSource("await");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText(source));
await dispatch(actions.paused(mockPauseInfo));
const getNextStepSpy = jest.spyOn(parser, "getNextStep");
@ -181,7 +180,6 @@ describe("pause", () => {
const source = makeSource("await");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText(source));
await dispatch(actions.paused(mockPauseInfo));
const getNextStepSpy = jest.spyOn(parser, "getNextStep");
@ -208,7 +206,6 @@ describe("pause", () => {
const source = makeSource("foo");
await dispatch(actions.newSource(source));
await dispatch(actions.newSource(makeOriginalSource("foo")));
await dispatch(actions.loadSourceText(source));
await dispatch(actions.paused(mockPauseInfo));
expect(selectors.getFrames(getState(), "FakeThread")).toEqual([
@ -216,6 +213,7 @@ describe("pause", () => {
generatedLocation: { column: 0, line: 1, sourceId: "foo" },
id: mockFrameId,
location: { column: 0, line: 1, sourceId: "foo" },
originalDisplayName: "foo",
scope: {
bindings: { arguments: [{ a: {} }], variables: { b: {} } }
},
@ -272,9 +270,6 @@ describe("pause", () => {
const fooOriginalSource = makeSource("foo-original");
await dispatch(actions.newSource(fooSource));
await dispatch(actions.newSource(fooOriginalSource));
await dispatch(actions.loadSourceText(fooSource));
await dispatch(actions.loadSourceText(fooOriginalSource));
await dispatch(actions.setSymbols("foo-original"));
await dispatch(actions.paused(mockPauseInfo));
expect(selectors.getFrames(getState(), "FakeThread")).toEqual([
@ -339,8 +334,6 @@ describe("pause", () => {
await dispatch(actions.newSource(source));
await dispatch(actions.newSource(originalSource));
await dispatch(actions.loadSourceText(source));
await dispatch(actions.loadSourceText(originalSource));
await dispatch(actions.paused(mockPauseInfo));
expect(selectors.getFrames(getState(), "FakeThread")).toEqual([

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

@ -88,7 +88,7 @@ export function searchSources(query: string) {
if (cancelled) {
return;
}
await dispatch(loadSourceText(source));
await dispatch(loadSourceText({ source }));
await dispatch(searchSource(source.id, query));
}
dispatch(updateSearchStatus(statusType.done));

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

@ -7,6 +7,7 @@
import { PROMISE } from "../utils/middleware/promise";
import {
getSource,
getSourceFromId,
getGeneratedSource,
getSourcesEpoch
} from "../../selectors";
@ -16,14 +17,17 @@ import { prettyPrintSource } from "./prettyPrint";
import * as parser from "../../workers/parser";
import { isLoaded, isOriginal, isPretty } from "../../utils/source";
import {
memoizeableAction,
type MemoizedAction
} from "../../utils/memoizableAction";
import { Telemetry } from "devtools-modules";
import type { ThunkArgs } from "../types";
import type { Source } from "../../types";
const requests = new Map();
// Measures the time it takes for a source to load
const loadSourceHistogram = "DEVTOOLS_DEBUGGER_LOAD_SOURCE_MS";
const telemetry = new Telemetry();
@ -69,13 +73,9 @@ async function loadSource(
async function loadSourceTextPromise(
source: Source,
epoch: number,
{ dispatch, getState, client, sourceMaps }: ThunkArgs
): Promise<?Source> {
if (isLoaded(source)) {
return source;
}
const epoch = getSourcesEpoch(getState());
await dispatch({
type: "LOAD_SOURCE_TEXT",
sourceId: source.id,
@ -84,50 +84,36 @@ async function loadSourceTextPromise(
});
const newSource = getSource(getState(), source.id);
if (!newSource) {
return;
}
if (!newSource.isWasm && isLoaded(newSource)) {
parser.setSource(newSource);
dispatch(setBreakpointPositions(newSource.id));
dispatch(setBreakpointPositions({ sourceId: newSource.id }));
}
return newSource;
}
/**
* @memberof actions/sources
* @static
*/
export function loadSourceText(inputSource: ?Source) {
return async (thunkArgs: ThunkArgs) => {
if (!inputSource) {
return;
}
// This ensures that the falsy check above is preserved into the IIFE
// below in a way that Flow is happy with.
const source = inputSource;
const epoch = getSourcesEpoch(thunkArgs.getState());
const id = `${epoch}:${source.id}`;
let promise = requests.get(id);
if (!promise) {
promise = (async () => {
try {
return await loadSourceTextPromise(source, epoch, thunkArgs);
} catch (e) {
// TODO: This swallows errors for now. Ideally we would get rid of
// this once we have a better handle on our async state management.
} finally {
requests.delete(id);
}
})();
requests.set(id, promise);
}
return promise;
export function loadSourceById(sourceId: string) {
return ({ getState, dispatch }: ThunkArgs) => {
const source = getSourceFromId(getState(), sourceId);
return dispatch(loadSourceText({ source }));
};
}
export const loadSourceText: MemoizedAction<
{ source: Source },
?Source
> = memoizeableAction("loadSourceText", {
exitEarly: ({ source }) => !source,
hasValue: ({ source }, { getState }) => isLoaded(source),
getValue: ({ source }, { getState }) => getSource(getState(), source.id),
createKey: ({ source }, { getState }) => {
const epoch = getSourcesEpoch(getState());
return `${epoch}:${source.id}`;
},
action: ({ source }, thunkArgs) => loadSourceTextPromise(source, thunkArgs)
});

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

@ -192,7 +192,7 @@ function checkPendingBreakpoints(sourceId: string) {
}
// load the source text if there is a pending breakpoint for it
await dispatch(loadSourceText(source));
await dispatch(loadSourceText({ source }));
await Promise.all(
pendingBreakpoints.map(bp => {
@ -248,7 +248,7 @@ export function newSources(sources: Source[]) {
// re-request new breakpoint positions.
for (const source of sourcesNeedingPositions) {
if (!hasBreakpointPositions(getState(), source.id)) {
dispatch(setBreakpointPositions(source.id));
dispatch(setBreakpointPositions({ sourceId: source.id }));
}
}

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

@ -79,6 +79,21 @@ export function createPrettySource(sourceId: string) {
};
}
function selectPrettyLocation(prettySource: Source) {
return async ({ dispatch, sourceMaps, getState }: ThunkArgs) => {
let location = getSelectedLocation(getState());
if (location) {
location = await sourceMaps.getOriginalLocation(location);
return dispatch(
selectSpecificLocation({ ...location, sourceId: prettySource.id })
);
}
return dispatch(selectSource(prettySource.id));
};
}
/**
* Toggle the pretty printing of a source's text. All subsequent calls to
* |getText| will return the pretty-toggled text. Nothing will happen for
@ -103,7 +118,7 @@ export function togglePrettyPrint(sourceId: string) {
}
if (!isLoaded(source)) {
await dispatch(loadSourceText(source));
await dispatch(loadSourceText({ source }));
}
assert(
@ -111,37 +126,22 @@ export function togglePrettyPrint(sourceId: string) {
"Pretty-printing only allowed on generated sources"
);
const selectedLocation = getSelectedLocation(getState());
const url = getPrettySourceURL(source.url);
const prettySource = getSourceByURL(getState(), url);
const options = {};
if (selectedLocation) {
options.location = await sourceMaps.getOriginalLocation(selectedLocation);
}
if (prettySource) {
const _sourceId = prettySource.id;
return dispatch(
selectSpecificLocation({ ...options.location, sourceId: _sourceId })
);
return dispatch(selectPrettyLocation(prettySource));
}
const newPrettySource = await dispatch(createPrettySource(sourceId));
await dispatch(selectPrettyLocation(newPrettySource));
await dispatch(remapBreakpoints(sourceId));
const threads = getSourceThreads(getState(), source);
await Promise.all(threads.map(thread => dispatch(mapFrames(thread))));
await dispatch(setSymbols(newPrettySource.id));
dispatch(
selectSpecificLocation({
...options.location,
sourceId: newPrettySource.id
})
);
await dispatch(setSymbols({ source: newPrettySource }));
return newPrettySource;
};

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

@ -145,7 +145,7 @@ export function selectLocation(
dispatch(setSelectedLocation(source, location));
await dispatch(loadSourceText(source));
await dispatch(loadSourceText({ source }));
const loadedSource = getSource(getState(), source.id);
if (!loadedSource) {
@ -164,7 +164,7 @@ export function selectLocation(
dispatch(closeTab(loadedSource));
}
dispatch(setSymbols(loadedSource.id));
dispatch(setSymbols({ source: loadedSource }));
dispatch(setOutOfScopeLocations());
// If a new source is selected update the file search results

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

@ -1,39 +1,56 @@
/* 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/>. */
import { getSourceFromId, getSourceThreads, getSymbols } from "../../selectors";
// @flow
import { hasSymbols, getSymbols } from "../../selectors";
import { PROMISE } from "../utils/middleware/promise";
import { mapFrames } from "../pause";
import { updateTab } from "../tabs";
import { loadSourceText } from "./loadSourceText";
import * as parser from "../../workers/parser";
import { isLoaded } from "../../utils/source";
import {
memoizeableAction,
type MemoizedAction
} from "../../utils/memoizableAction";
import type { SourceId } from "../../types";
import type { ThunkArgs } from "../types";
import type { Source } from "../../types";
import type { Symbols } from "../../reducers/types";
export function setSymbols(sourceId: SourceId) {
return async ({ dispatch, getState, sourceMaps }: ThunkArgs) => {
const source = getSourceFromId(getState(), sourceId);
async function doSetSymbols(source, { dispatch, getState }) {
const sourceId = source.id;
if (source.isWasm || getSymbols(getState(), source) || !isLoaded(source)) {
return;
}
if (!isLoaded(source)) {
await dispatch(loadSourceText({ source }));
}
await dispatch({
type: "SET_SYMBOLS",
sourceId,
[PROMISE]: parser.getSymbols(sourceId)
});
await dispatch({
type: "SET_SYMBOLS",
sourceId,
[PROMISE]: parser.getSymbols(sourceId)
});
const threads = getSourceThreads(getState(), source);
await Promise.all(threads.map(thread => dispatch(mapFrames(thread))));
const symbols = getSymbols(getState(), source);
if (symbols && symbols.framework) {
dispatch(updateTab(source, symbols.framework));
}
const symbols = getSymbols(getState(), source);
if (symbols.framework) {
dispatch(updateTab(source, symbols.framework));
}
};
return symbols;
}
type Args = { source: Source };
export const setSymbols: MemoizedAction<Args, ?Symbols> = memoizeableAction(
"setSymbols",
{
exitEarly: ({ source }) => source.isWasm,
hasValue: ({ source }, { getState }) => hasSymbols(getState(), source),
getValue: ({ source }, { getState }) => getSymbols(getState(), source),
createKey: ({ source }) => source.id,
action: ({ source }, thunkArgs) => doSetSymbols(source, thunkArgs)
}
);

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

@ -25,7 +25,7 @@ describe("loadSourceText", () => {
const foo1Source = makeSource("foo1");
await dispatch(actions.newSource(foo1Source));
await dispatch(actions.loadSourceText(foo1Source));
await dispatch(actions.loadSourceText({ source: foo1Source }));
const fooSource = selectors.getSource(getState(), "foo1");
if (!fooSource || typeof fooSource.text != "string") {
@ -35,7 +35,7 @@ describe("loadSourceText", () => {
const baseFoo2Source = makeSource("foo2");
await dispatch(actions.newSource(baseFoo2Source));
await dispatch(actions.loadSourceText(baseFoo2Source));
await dispatch(actions.loadSourceText({ source: baseFoo2Source }));
const foo2Source = selectors.getSource(getState(), "foo2");
if (!foo2Source || typeof foo2Source.text != "string") {
@ -84,21 +84,12 @@ describe("loadSourceText", () => {
column: 0
};
await dispatch(actions.addBreakpoint(location, {}));
const breakpoint = selectors.getBreakpoint(getState(), location);
if (!breakpoint) {
throw new Error("no breakpoint");
}
expect(breakpoint.text).toBe("var fooGen = 42;");
expect(breakpoint.originalText).toBe("var fooOrig = 42;");
await dispatch(actions.loadSourceText(fooOrigSource));
const breakpoint1 = getBreakpointsList(getState())[0];
expect(breakpoint1.text).toBe("var fooGen = 42;");
expect(breakpoint1.originalText).toBe("var fooOrig = 42;");
await dispatch(actions.loadSourceText(fooGenSource));
await dispatch(actions.loadSourceText({ source: fooGenSource }));
const breakpoint2 = getBreakpointsList(getState())[0];
expect(breakpoint2.text).toBe("var fooGen = 42;");
@ -121,11 +112,11 @@ describe("loadSourceText", () => {
await dispatch(actions.newSource(baseSource));
let source = selectors.getSource(getState(), id);
dispatch(actions.loadSourceText(source));
let source = selectors.getSourceFromId(getState(), id);
dispatch(actions.loadSourceText({ source }));
source = selectors.getSource(getState(), id);
const loading = dispatch(actions.loadSourceText(source));
source = selectors.getSourceFromId(getState(), id);
const loading = dispatch(actions.loadSourceText({ source }));
if (!resolve) {
throw new Error("no resolve");
@ -153,8 +144,8 @@ describe("loadSourceText", () => {
const baseSource = makeSource(id, { loadedState: "unloaded" });
await dispatch(actions.newSource(baseSource));
let source = selectors.getSource(getState(), id);
const loading = dispatch(actions.loadSourceText(source));
let source = selectors.getSourceFromId(getState(), id);
const loading = dispatch(actions.loadSourceText({ source }));
if (!resolve) {
throw new Error("no resolve");
@ -162,8 +153,8 @@ describe("loadSourceText", () => {
resolve({ source: "yay", contentType: "text/javascript" });
await loading;
source = selectors.getSource(getState(), id);
await dispatch(actions.loadSourceText(source));
source = selectors.getSourceFromId(getState(), id);
await dispatch(actions.loadSourceText({ source }));
expect(count).toEqual(1);
source = selectors.getSource(getState(), id);
@ -174,10 +165,11 @@ describe("loadSourceText", () => {
const { dispatch, getState } = createStore(sourceThreadClient);
const source = makeSource("foo1");
await dispatch(actions.loadSourceText(source));
const prevSource = selectors.getSource(getState(), "foo1");
dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText({ source }));
const prevSource = selectors.getSourceFromId(getState(), "foo1");
await dispatch(actions.loadSourceText(prevSource));
await dispatch(actions.loadSourceText({ source: prevSource }));
const curSource = selectors.getSource(getState(), "foo1");
expect(prevSource === curSource).toBeTruthy();
@ -195,7 +187,7 @@ describe("loadSourceText", () => {
return fooSource && fooSource.loadedState === "loading";
});
await dispatch(actions.loadSourceText(source));
await dispatch(actions.loadSourceText({ source }));
expect(wasLoading()).toBe(true);
});
@ -205,7 +197,7 @@ describe("loadSourceText", () => {
const source = makeSource("bad-id");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText(source));
await dispatch(actions.loadSourceText({ source }));
const badSource = selectors.getSource(getState(), "bad-id");
if (!badSource || !badSource.error) {

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

@ -17,7 +17,6 @@ import {
import readFixture from "./helpers/readFixture";
const {
getSource,
getSymbols,
getOutOfScopeLocations,
getInScopeLines,
@ -70,8 +69,10 @@ describe("ast", () => {
const { dispatch, getState } = store;
const base = makeSource("base.js");
await dispatch(actions.newSource(base));
await dispatch(actions.loadSourceText(base));
await dispatch(actions.setSymbols("base.js"));
await dispatch(actions.loadSourceText({ source: base }));
const loadedSource = selectors.getSourceFromId(getState(), base.id);
await dispatch(actions.setSymbols({ source: loadedSource }));
await waitForState(store, state => !isSymbolsLoading(state, base));
const baseSymbols = getSymbols(getState(), base);
@ -108,10 +109,9 @@ describe("ast", () => {
await dispatch(actions.newSource(source));
await dispatch(
actions.loadSourceText(getSource(getState(), source.id))
);
await dispatch(actions.setSymbols(source.id));
await dispatch(actions.loadSourceText({ source }));
const loadedSource = selectors.getSourceFromId(getState(), source.id);
await dispatch(actions.setSymbols({ source: loadedSource }));
expect(getFramework(getState(), source)).toBe("React");
});
@ -121,8 +121,8 @@ describe("ast", () => {
const { dispatch, getState } = store;
const base = makeSource("base.js");
await dispatch(actions.newSource(base));
await dispatch(actions.loadSourceText(base));
await dispatch(actions.setSymbols("base.js"));
await dispatch(actions.loadSourceText({ source: base }));
await dispatch(actions.setSymbols({ source: base }));
expect(getFramework(getState(), base)).toBe(undefined);
});

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

@ -37,6 +37,7 @@ const mockThreadClient = {
),
getFrameScopes: async () => {},
sourceContents: () => ({ source: "", contentType: "text/javascript" }),
getBreakpointPositions: async () => [],
autocomplete: () => {
return new Promise(resolve => {
resolve({
@ -61,7 +62,6 @@ describe("expressions", () => {
dispatch(actions.addExpression((undefined: any)));
dispatch(actions.addExpression(""));
expect(selectors.getExpressions(getState()).size).toBe(0);
});
@ -97,12 +97,10 @@ describe("expressions", () => {
await dispatch(actions.addExpression("foo"));
await dispatch(actions.addExpression("bar"));
expect(selectors.getExpressions(getState()).size).toBe(2);
const expression = selectors.getExpression(getState(), "foo");
dispatch(actions.deleteExpression(expression));
expect(selectors.getExpressions(getState()).size).toBe(1);
expect(selectors.getExpression(getState(), "bar").input).toBe("bar");
});
@ -112,12 +110,10 @@ describe("expressions", () => {
await dispatch(actions.addExpression("foo"));
await dispatch(actions.addExpression("bar"));
expect(selectors.getExpression(getState(), "foo").value).toBe("bla");
expect(selectors.getExpression(getState(), "bar").value).toBe("bla");
await dispatch(actions.evaluateExpressions());
expect(selectors.getExpression(getState(), "foo").value).toBe("bla");
expect(selectors.getExpression(getState(), "bar").value).toBe("bla");
});
@ -125,9 +121,7 @@ describe("expressions", () => {
it("should evaluate expressions in specific scope", async () => {
const { dispatch, getState } = createStore(mockThreadClient);
await createFrames(dispatch);
await dispatch(actions.newSource(makeSource("source")));
await dispatch(actions.addExpression("foo"));
await dispatch(actions.addExpression("bar"));
@ -142,17 +136,15 @@ describe("expressions", () => {
it("should get the autocomplete matches for the input", async () => {
const { dispatch, getState } = createStore(mockThreadClient);
await dispatch(actions.autocomplete("to", 2));
expect(selectors.getAutocompleteMatchset(getState())).toMatchSnapshot();
});
});
async function createFrames(dispatch) {
const frame = makeMockFrame();
await dispatch(actions.newSource(makeSource("example.js")));
await dispatch(actions.newSource(makeSource("source")));
await dispatch(
actions.paused({

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

@ -78,7 +78,7 @@ describe("when adding breakpoints", () => {
const source = makeSource("foo.js");
await dispatch(actions.newSource(source));
await dispatch(actions.newSource(makeSource("foo.js")));
await dispatch(actions.loadSourceText(source));
await dispatch(actions.loadSourceText({ source }));
const bp = generateBreakpoint("foo.js", 5, 1);
const id = makePendingLocationId(bp.location);
@ -119,8 +119,8 @@ describe("when adding breakpoints", () => {
await dispatch(actions.newSource(source1));
await dispatch(actions.newSource(source2));
await dispatch(actions.loadSourceText(source1));
await dispatch(actions.loadSourceText(source2));
await dispatch(actions.loadSourceText({ source: source1 }));
await dispatch(actions.loadSourceText({ source: source2 }));
await dispatch(actions.addBreakpoint(breakpoint1.location));
await dispatch(actions.addBreakpoint(breakpoint2.location));
@ -144,7 +144,7 @@ describe("when adding breakpoints", () => {
const source = makeSource("foo");
await dispatch(actions.newSource(makeSource("foo")));
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(
actions.addBreakpoint(breakpoint1.location, { hidden: true })
@ -170,8 +170,8 @@ describe("when adding breakpoints", () => {
await dispatch(actions.newSource(source1));
await dispatch(actions.newSource(source2));
await dispatch(actions.loadSourceText(source1));
await dispatch(actions.loadSourceText(source2));
await dispatch(actions.loadSourceText({ source: source1 }));
await dispatch(actions.loadSourceText({ source: source2 }));
await dispatch(actions.addBreakpoint(breakpoint1.location));
await dispatch(actions.addBreakpoint(breakpoint2.location));
@ -197,7 +197,7 @@ describe("when changing an existing breakpoint", () => {
const source = makeSource("foo");
await dispatch(actions.newSource(source));
await dispatch(actions.newSource(makeSource("foo")));
await dispatch(actions.loadSourceText(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.addBreakpoint(bp.location));
await dispatch(
@ -221,7 +221,7 @@ describe("when changing an existing breakpoint", () => {
const source = makeSource("foo");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.addBreakpoint(bp.location));
await dispatch(actions.disableBreakpoint(bp));
@ -241,7 +241,7 @@ describe("when changing an existing breakpoint", () => {
const source = makeSource("foo.js");
await dispatch(actions.newSource(source));
await dispatch(actions.newSource(makeSource("foo.js")));
await dispatch(actions.loadSourceText(source));
await dispatch(actions.loadSourceText({ source }));
const id = makePendingLocationId(bp.location);
@ -278,7 +278,7 @@ describe("initializing when pending breakpoints exist in prefs", () => {
const source = makeSource("bar.js");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.addBreakpoint(bar.location));
const bps = selectors.getPendingBreakpointList(getState());
@ -296,7 +296,7 @@ describe("initializing when pending breakpoints exist in prefs", () => {
const source = makeSource("foo.js");
await dispatch(actions.newSource(source));
await dispatch(actions.newSource(makeSource("foo.js")));
await dispatch(actions.loadSourceText(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.addBreakpoint(bp.location));
@ -318,7 +318,7 @@ describe("initializing with disabled pending breakpoints in prefs", () => {
await dispatch(actions.newSource(makeSource("bar.js")));
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText(source));
await dispatch(actions.loadSourceText({ source }));
await waitForState(store, state => {
const bps = selectors.getBreakpointsForSource(state, source.id);
@ -354,7 +354,7 @@ describe("adding sources", () => {
await dispatch(actions.newSource(makeSource("bar.js")));
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText(source));
await dispatch(actions.loadSourceText({ source }));
await waitForState(store, state => selectors.getBreakpointCount(state) > 0);
@ -405,8 +405,8 @@ describe("adding sources", () => {
await dispatch(actions.newSource(makeSource("bar.js")));
await dispatch(actions.newSource(makeSource("foo.js")));
await dispatch(actions.newSources([source1, source2]));
await dispatch(actions.loadSourceText(source1));
await dispatch(actions.loadSourceText(source2));
await dispatch(actions.loadSourceText({ source: source1 }));
await dispatch(actions.loadSourceText({ source: source2 }));
await waitForState(store, state => selectors.getBreakpointCount(state) > 0);
expect(selectors.getBreakpointCount(getState())).toEqual(1);

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

@ -68,7 +68,12 @@ describe("project text search", () => {
});
it("should ignore sources with minified versions", async () => {
const source1 = makeSource("bar", { sourceMapURL: "bar:formatted" });
const source1 = makeSource("bar", {
sourceMapURL: "bar:formatted",
loadedState: "loaded",
source: "function bla(x, y) { const bar = 4; return 2;}",
contentType: "text/javascript"
});
const source2 = makeSource("bar:formatted");
const mockMaps = {
@ -76,6 +81,7 @@ describe("project text search", () => {
source: "function bla(x, y) {\n const bar = 4; return 2;\n}",
contentType: "text/javascript"
}),
applySourceMap: async () => {},
getOriginalURLs: async () => [source2.url],
getGeneratedRangesForOriginal: async () => [],
getOriginalLocations: async items => items
@ -98,7 +104,7 @@ describe("project text search", () => {
const source = makeSource("bar");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText(source));
await dispatch(actions.loadSourceText({ source }));
dispatch(actions.addSearchQuery("bla"));

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

@ -42,15 +42,6 @@ function isDocumentReady(source, frame) {
export class DebugLine extends Component<Props> {
debugExpression: null;
componentDidUpdate(prevProps: Props) {
const { why, frame, source } = this.props;
startOperation();
this.clearDebugLine(prevProps.why, prevProps.frame, prevProps.source);
this.setDebugLine(why, frame, source);
endOperation();
}
componentDidMount() {
const { why, frame, source } = this.props;
this.setDebugLine(why, frame, source);
@ -61,6 +52,15 @@ export class DebugLine extends Component<Props> {
this.clearDebugLine(why, frame, source);
}
componentDidUpdate(prevProps: Props) {
const { why, frame, source } = this.props;
startOperation();
this.clearDebugLine(prevProps.why, prevProps.frame, prevProps.source);
this.setDebugLine(why, frame, source);
endOperation();
}
setDebugLine(why: Why, frame: Frame, source: Source) {
if (!isDocumentReady(source, frame)) {
return;

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

@ -54,7 +54,6 @@ import ConditionalPanel from "./ConditionalPanel";
import {
showSourceText,
updateDocument,
showLoading,
showErrorMessage,
getEditor,
@ -127,25 +126,25 @@ class Editor extends PureComponent<Props, State> {
};
}
componentWillReceiveProps(nextProps) {
if (!this.state.editor) {
return;
componentWillReceiveProps(nextProps: Props) {
let editor = this.state.editor;
if (!this.state.editor && nextProps.selectedSource) {
editor = this.setupEditor();
}
startOperation();
resizeBreakpointGutter(this.state.editor.codeMirror);
resizeToggleButton(this.state.editor.codeMirror);
endOperation();
}
this.setText(nextProps, editor);
this.setSize(nextProps, editor);
this.scrollToLocation(nextProps, editor);
componentWillUpdate(nextProps) {
if (!this.state.editor) {
return;
if (this.props.selectedSource != nextProps.selectedSource) {
this.props.updateViewport();
resizeBreakpointGutter(editor.codeMirror);
resizeToggleButton(editor.codeMirror);
}
this.setText(nextProps);
this.setSize(nextProps);
this.scrollToLocation(nextProps);
endOperation();
}
setupEditor() {
@ -163,11 +162,6 @@ class Editor extends PureComponent<Props, State> {
const { codeMirror } = editor;
const codeMirrorWrapper = codeMirror.getWrapperElement();
startOperation();
resizeBreakpointGutter(codeMirror);
resizeToggleButton(codeMirror);
endOperation();
codeMirror.on("gutterClick", this.onGutterClick);
// Set code editor wrapper to be focusable
@ -259,26 +253,6 @@ class Editor extends PureComponent<Props, State> {
shortcuts.off(searchAgainKey);
}
componentDidUpdate(prevProps, prevState) {
const { selectedSource } = this.props;
// NOTE: when devtools are opened, the editor is not set when
// the source loads so we need to wait until the editor is
// set to update the text and size.
if (!prevState.editor && selectedSource) {
if (!this.state.editor) {
const editor = this.setupEditor();
updateDocument(editor, selectedSource);
} else {
this.setText(this.props);
this.setSize(this.props);
}
}
if (prevProps.selectedSource != selectedSource) {
this.props.updateViewport();
}
}
getCurrentLine() {
const { codeMirror } = this.state.editor;
const { selectedSource } = this.props;
@ -487,10 +461,8 @@ class Editor extends PureComponent<Props, State> {
);
};
shouldScrollToLocation(nextProps) {
shouldScrollToLocation(nextProps, editor) {
const { selectedLocation, selectedSource } = this.props;
const { editor } = this.state;
if (
!editor ||
!nextProps.selectedSource ||
@ -510,11 +482,10 @@ class Editor extends PureComponent<Props, State> {
return isFirstLoad || locationChanged || symbolsChanged;
}
scrollToLocation(nextProps) {
const { editor } = this.state;
scrollToLocation(nextProps, editor) {
const { selectedLocation, selectedSource } = nextProps;
if (selectedLocation && this.shouldScrollToLocation(nextProps)) {
if (selectedLocation && this.shouldScrollToLocation(nextProps, editor)) {
let { line, column } = toEditorPosition(selectedLocation);
if (selectedSource && hasDocument(selectedSource.id)) {
@ -522,12 +493,13 @@ class Editor extends PureComponent<Props, State> {
const lineText: ?string = doc.getLine(line);
column = Math.max(column, getIndentation(lineText));
}
scrollToColumn(editor.codeMirror, line, column);
}
}
setSize(nextProps) {
if (!this.state.editor) {
setSize(nextProps, editor) {
if (!editor) {
return;
}
@ -535,14 +507,14 @@ class Editor extends PureComponent<Props, State> {
nextProps.startPanelSize !== this.props.startPanelSize ||
nextProps.endPanelSize !== this.props.endPanelSize
) {
this.state.editor.codeMirror.setSize();
editor.codeMirror.setSize();
}
}
setText(props) {
setText(props, editor) {
const { selectedSource, symbols } = props;
if (!this.state.editor) {
if (!editor) {
return;
}
@ -552,7 +524,7 @@ class Editor extends PureComponent<Props, State> {
}
if (!isLoaded(selectedSource)) {
return showLoading(this.state.editor);
return showLoading(editor);
}
if (selectedSource.error) {
@ -560,7 +532,7 @@ class Editor extends PureComponent<Props, State> {
}
if (selectedSource) {
return showSourceText(this.state.editor, selectedSource, symbols);
return showSourceText(editor, selectedSource, symbols);
}
}

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

@ -16,7 +16,9 @@ import type { Action, DonePromiseAction } from "../actions/types";
type EmptyLinesType = number[];
export type Symbols = SymbolDeclarations | {| loading: true |};
export type LoadedSymbols = SymbolDeclarations;
export type Symbols = LoadedSymbols | {| loading: true |};
export type EmptyLinesMap = { [k: string]: EmptyLinesType };
export type SymbolsMap = { [k: string]: Symbols };

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

@ -503,6 +503,14 @@ export function getGeneratedSource(
return getSourceFromId(state, originalToGeneratedId(source.id));
}
export function getGeneratedSourceById(
state: OuterState,
sourceId: string
): Source {
const generatedSourceId = originalToGeneratedId(sourceId);
return getSourceFromId(state, generatedSourceId);
}
export function getPendingSelectedLocation(state: OuterState) {
return state.sources.pendingSelectedLocation;
}

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

@ -50,4 +50,4 @@ export type { SourcesMap, SourcesMapByThread } from "./sources";
export type { ActiveSearchType, OrientationType } from "./ui";
export type { BreakpointsMap, XHRBreakpointsList } from "./breakpoints";
export type { Command } from "./pause";
export type { Symbols } from "./ast";
export type { LoadedSymbols, Symbols } from "./ast";

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

@ -1,7 +1,7 @@
// @flow
/* 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/>. */
// @flow
import { groupBy } from "lodash";
import { createSelector } from "reselect";
@ -164,7 +164,7 @@ export const visibleColumnBreakpoints: Selector<
export function getFirstBreakpointPosition(
state: State,
{ line, sourceId }: SourceLocation
) {
): ?BreakpointPosition {
const positions = getBreakpointPositionsForSource(state, sourceId);
const source = getSource(state, sourceId);

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

@ -4,7 +4,6 @@
// @flow
import { getSymbols } from "../../workers/parser";
import { findClosestFunction } from "../ast";
import type { SourceLocation, Source, ASTLocation } from "../../types";
@ -33,13 +32,15 @@ export function getASTLocation(
return { name: undefined, offset: location, index: 0 };
}
export async function findFunctionByName(
source: Source,
export function findFunctionByName(
symbols: Symbols,
name: ?string,
index: number
) {
const symbols = await getSymbols(source.id);
const functions = symbols.functions;
if (symbols.loading) {
return null;
}
const functions = symbols.functions;
return functions.find(node => node.name === name && node.index === index);
}

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

@ -0,0 +1,84 @@
/* 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/>. */
// @flow
import type { ThunkArgs } from "../actions/types";
export type MemoizedAction<
Args,
Result
> = Args => ThunkArgs => Promise<?Result>;
type MemoizableActionParams<Args, Result> = {
exitEarly?: (args: Args, thunkArgs: ThunkArgs) => boolean,
hasValue: (args: Args, thunkArgs: ThunkArgs) => boolean,
getValue: (args: Args, thunkArgs: ThunkArgs) => Result,
createKey: (args: Args, thunkArgs: ThunkArgs) => string,
action: (args: Args, thunkArgs: ThunkArgs) => Promise<Result>
};
/*
* memoizableActon is a utility for actions that should only be performed
* once per key. It is useful for loading sources, parsing symbols ...
*
* @exitEarly - if true, do not attempt to perform the action
* @hasValue - checks to see if the result is in the redux store
* @getValue - gets the result from the redux store
* @createKey - creates a key for the requests map
* @action - kicks off the async work for the action
*
*
* For Example
*
* export const setItem = memoizeableAction(
* "setItem",
* {
* hasValue: ({ a }, { getState }) => hasItem(getState(), a),
* getValue: ({ a }, { getState }) => getItem(getState(), a),
* createKey: ({ a }) => a,
* action: ({ a }, thunkArgs) => doSetItem(a, thunkArgs)
* }
* );
*
*/
export function memoizeableAction<Args, Result>(
name: string,
{
hasValue,
getValue,
createKey,
action,
exitEarly
}: MemoizableActionParams<Args, Result>
): MemoizedAction<Args, Result> {
const requests = new Map();
return args => async (thunkArgs: ThunkArgs) => {
if (exitEarly && exitEarly(args, thunkArgs)) {
return;
}
if (hasValue(args, thunkArgs)) {
return getValue(args, thunkArgs);
}
const key = createKey(args, thunkArgs);
if (!requests.has(key)) {
requests.set(
key,
(async () => {
try {
await action(args, thunkArgs);
} catch (e) {
console.warn(`Action ${name} had an exception:`, e);
} finally {
requests.delete(key);
}
})()
);
}
await requests.get(key);
return getValue(args, thunkArgs);
};
}

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

@ -31,6 +31,7 @@ CompiledModules(
'log.js',
'makeRecord.js',
'memoize.js',
'memoizableAction.js',
'path.js',
'prefs.js',
'preview.js',

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

@ -636,6 +636,7 @@ support-files =
examples/doc-pause-points.html
examples/doc-return-values.html
examples/doc-wasm-sourcemaps.html
examples/doc-audiocontext.html
examples/asm.js
examples/async.js
examples/bogus-map.js
@ -665,6 +666,7 @@ support-files =
examples/doc-sourceURL-breakpoint.html
[browser_dbg-asm.js]
[browser_dbg-audiocontext.js]
[browser_dbg-async-stepping.js]
[browser_dbg-sourcemapped-breakpoint-console.js]
skip-if = (os == "win" && ccov) # Bug 1453549

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

@ -0,0 +1,18 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Test the AudioContext are paused and resume appropriately when using the
// debugger.
add_task(async function() {
const dbg = await initDebugger("doc-audiocontext.html");
invokeInTab("myFunction");
invokeInTab("suspendAC");
invokeInTab("debuggerStatement");
await waitForPaused(dbg);
invokeInTab("checkACState");
ok(true, "No AudioContext state transition are caused by the debugger")
});

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

@ -1,5 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/* 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/>. */
function clickButton(dbg, button) {
const resumeFired = waitForDispatch(dbg, "COMMAND");

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

@ -1,10 +1,12 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/* 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/>. */
// Tests pretty-printing a source that is currently paused.
add_task(async function() {
const dbg = await initDebugger("doc-minified.html", "math.min.js");
const thread = dbg.selectors.getCurrentThread(dbg.getState());
await selectSource(dbg, "math.min.js");
await addBreakpoint(dbg, "math.min.js", 2);
@ -15,7 +17,12 @@ add_task(async function() {
clickElement(dbg, "prettyPrintButton");
await waitForSelectedSource(dbg, "math.min.js:formatted");
await waitForState(
dbg,
state => dbg.selectors.getSelectedFrame(state, thread).location.line == 18
);
assertPausedLocation(dbg);
await assertEditorBreakpoint(dbg, 18, true);
await resume(dbg);
});

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

@ -7,7 +7,9 @@ add_task(async function() {
const dbg = await initDebugger("doc-xhr-run-to-completion.html");
invokeInTab("singleRequest", "doc-xhr-run-to-completion.html");
await waitForPaused(dbg);
await waitForSelectedLocation(dbg, 23);
assertPausedLocation(dbg);
resume(dbg);
await once(Services.ppmm, "test passed");
});

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

@ -0,0 +1,48 @@
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Debugger test page</title>
</head>
<body>
<button id="start" onclick="myFunction()">start ac</button>
<button id="suspend" onclick="suspendAC()">suspend ac</button>
<button id="break" onclick="debuggerStatement()">break</button>
<button id="check" onclick="checkACState()">check ac state</button>
<script type="text/javascript">
var ac = null;
var suspend_called = false;
function suspendAC() {
suspend_called = true;
ac.suspend();
}
function debuggerStatement() {
debugger;
}
function checkACState() {
if (ac.state != "suspended") {
throw "AudioContext should be suspended.";
}
}
function myFunction() {
ac = new AudioContext();
function statechange_suspend() {
ac.onstatechange = statechange_fail;
}
function statechange_fail() {
throw "No state change should occur when paused in the debugger.";
}
ac.onstatechange = function() {
ac.onstatechange = statechange_suspend;
}
}
</script>
</body>
</html>

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

@ -207,6 +207,16 @@ async function waitForElementWithSelector(dbg, selector) {
return findElementWithSelector(dbg, selector);
}
function waitForSelectedLocation(dbg, line ) {
return waitForState(
dbg,
state => {
const location = dbg.selectors.getSelectedLocation(state)
return location && location.line == line
}
);
}
function waitForSelectedSource(dbg, url) {
const {
getSelectedSource,

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

@ -13,6 +13,7 @@ const FontName = createFactory(require("./FontName"));
const FontSize = createFactory(require("./FontSize"));
const FontStyle = createFactory(require("./FontStyle"));
const FontWeight = createFactory(require("./FontWeight"));
const LetterSpacing = createFactory(require("./LetterSpacing"));
const LineHeight = createFactory(require("./LineHeight"));
const { getStr } = require("../utils/l10n");
@ -161,6 +162,15 @@ class FontEditor extends PureComponent {
});
}
renderLetterSpacing(value) {
return value !== null && LetterSpacing({
key: `${this.props.fontEditor.id}:letter-spacing`,
disabled: this.props.fontEditor.disabled,
onChange: this.props.onPropertyChange,
value,
});
}
renderFontStyle(value) {
return value && FontStyle({
onChange: this.props.onPropertyChange,
@ -283,6 +293,8 @@ class FontEditor extends PureComponent {
this.renderFontSize(properties["font-size"]),
// Always render UI for line height.
this.renderLineHeight(properties["line-height"]),
// Always render UI for letter spacing.
this.renderLetterSpacing(properties["letter-spacing"]),
// Render UI for font weight if no "wght" registered axis is defined.
!hasWeightAxis && this.renderFontWeight(properties["font-weight"]),
// Render UI for font style if no "slnt" or "ital" registered axis is defined.

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

@ -19,6 +19,8 @@ class FontPropertyValue extends PureComponent {
return {
// Whether to allow input values above the value defined by the `max` prop.
allowOverflow: PropTypes.bool,
// Whether to allow input values below the value defined by the `min` prop.
allowUnderflow: PropTypes.bool,
className: PropTypes.string,
defaultValue: PropTypes.number,
disabled: PropTypes.bool.isRequired,
@ -34,20 +36,28 @@ class FontPropertyValue extends PureComponent {
nameLabel: PropTypes.bool,
onChange: PropTypes.func.isRequired,
step: PropTypes.number,
// Whether to show the value input field.
showInput: PropTypes.bool,
// Whether to show the unit select dropdown.
showUnit: PropTypes.bool,
unit: PropTypes.string,
unitOptions: PropTypes.array,
value: PropTypes.number,
valueLabel: PropTypes.string,
};
}
static get defaultProps() {
return {
allowOverflow: false,
allowUnderflow: false,
className: "",
minLabel: false,
maxLabel: false,
nameLabel: false,
step: 1,
showInput: true,
showUnit: true,
unit: null,
unitOptions: [],
};
@ -93,7 +103,7 @@ class FontPropertyValue extends PureComponent {
/**
* Check if the given value is valid according to the constraints of this component.
* Ensure it is a number and that it does not go outside the min/max limits, unless
* allowed by the `allowOverflow` props flag.
* allowed by the `allowOverflow` and `allowUnderflow` props.
*
* @param {Number} value
* Numeric value
@ -101,18 +111,19 @@ class FontPropertyValue extends PureComponent {
* Whether the value conforms to the components contraints.
*/
isValueValid(value) {
const { allowOverflow, min, max } = this.props;
const { allowOverflow, allowUnderflow, min, max } = this.props;
if (typeof value !== "number" || isNaN(value)) {
return false;
}
if (min !== undefined && value < min) {
// Ensure it does not go below minimum value, unless underflow is allowed.
if (min !== undefined && value < min && !allowUnderflow) {
return false;
}
// Ensure it does not exceed maximum value, unless overflow is allowed.
if (max !== undefined && value > this.props.max && !allowOverflow) {
// Ensure it does not go over maximum value, unless overflow is allowed.
if (max !== undefined && value > max && !allowOverflow) {
return false;
}
@ -328,6 +339,14 @@ class FontPropertyValue extends PureComponent {
return createElement(Fragment, null, labelEl, detailEl);
}
renderValueLabel() {
if (!this.props.valueLabel) {
return null;
}
return dom.div({ className: "font-value-label" }, this.props.valueLabel);
}
render() {
// Guard against bad axis data.
if (this.props.min === this.props.max) {
@ -366,6 +385,8 @@ class FontPropertyValue extends PureComponent {
const input = dom.input(
{
...defaults,
// Remove lower limit from number input if it is allowed to underflow.
min: this.props.allowUnderflow ? null : this.props.min,
// Remove upper limit from number input if it is allowed to overflow.
max: this.props.allowOverflow ? null : this.props.max,
name: this.props.name,
@ -399,8 +420,9 @@ class FontPropertyValue extends PureComponent {
},
range
),
input,
this.renderUnitSelect()
this.renderValueLabel(),
this.props.showInput && input,
this.props.showUnit && this.renderUnitSelect()
)
);
}

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

@ -0,0 +1,96 @@
/* 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 { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const FontPropertyValue = createFactory(require("./FontPropertyValue"));
const { getStr } = require("../utils/l10n");
const { getUnitFromValue, getStepForUnit } = require("../utils/font-utils");
class LineHeight extends PureComponent {
static get propTypes() {
return {
disabled: PropTypes.bool.isRequired,
onChange: PropTypes.func.isRequired,
value: PropTypes.string.isRequired,
};
}
constructor(props) {
super(props);
// Local state for min/max bounds indexed by unit to allow user input that
// goes out-of-bounds while still providing a meaningful default range. The indexing
// by unit is needed to account for unit conversion (ex: em to px) where the operation
// may result in out-of-bounds values. Avoiding React's state and setState() because
// `value` is a prop coming from the Redux store while min/max are local. Reconciling
// value/unit changes is needlessly complicated and adds unnecessary re-renders.
this.historicMin = {};
this.historicMax = {};
}
getDefaultMinMax(unit) {
let min;
let max;
switch (unit) {
case "px":
min = -10;
max = 10;
break;
default:
min = -0.2;
max = 0.6;
break;
}
return { min, max };
}
render() {
// For a unitless or a NaN value, default unit to "em".
const unit = getUnitFromValue(this.props.value) || "em";
// When the initial value of "letter-spacing" is "normal", the parsed value
// is not a number (NaN). Guard by setting the default value to 0.
let value = parseFloat(this.props.value);
const hasKeywordValue = isNaN(value);
value = isNaN(value) ? 0 : value;
let { min, max } = this.getDefaultMinMax(unit);
min = Math.min(min, value);
max = Math.max(max, value);
// Allow lower and upper bounds to move to accomodate the incoming value.
this.historicMin[unit] = this.historicMin[unit]
? Math.min(this.historicMin[unit], min)
: min;
this.historicMax[unit] = this.historicMax[unit]
? Math.max(this.historicMax[unit], max)
: max;
return FontPropertyValue({
allowOverflow: true,
allowUnderflow: true,
disabled: this.props.disabled,
label: getStr("fontinspector.letterSpacingLabel"),
min: this.historicMin[unit],
max: this.historicMax[unit],
name: "letter-spacing",
onChange: this.props.onChange,
// Increase the increment granularity because letter spacing is very sensitive.
step: getStepForUnit(unit) / 100,
// Show the value input and unit only when the value is not a keyword.
showInput: !hasKeywordValue,
showUnit: !hasKeywordValue,
unit,
unitOptions: ["em", "rem", "px"],
value,
// Show the value as a read-only label if it's a keyword.
valueLabel: hasKeywordValue ? this.props.value : null,
});
}
}
module.exports = LineHeight;

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

@ -19,5 +19,6 @@ DevToolsModules(
'FontSize.js',
'FontStyle.js',
'FontWeight.js',
'LetterSpacing.js',
'LineHeight.js',
)

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

@ -42,6 +42,7 @@ const FONT_PROPERTIES = [
"font-style",
"font-variation-settings",
"font-weight",
"letter-spacing",
"line-height",
];
const REGISTERED_AXES_TO_FONT_PROPERTIES = {
@ -144,6 +145,7 @@ class FontInspector {
throw TypeError(`Invalid value for conversion. Expected Number, got ${value}`);
}
// Early return with the same value if conversion is not required.
if (fromUnit === toUnit || value === 0) {
return value;
}
@ -165,15 +167,9 @@ class FontInspector {
const fromPx = fromUnit === "px";
// Determine the target CSS unit for conversion.
const unit = toUnit === "px" ? fromUnit : toUnit;
// NodeFront instance of selected/target element.
const node = this.node;
// Reference node based on which to convert relative sizes like "em" and "%".
const referenceNode = (property === "line-height") ? node : node.parentNode();
// Default output value to input value for a 1-to-1 conversion as a guard against
// unrecognized CSS units. It will not be correct, but it will also not break.
let out = value;
// Computed style for reference node used for conversion of "em", "rem", "%".
let computedStyle;
if (unit === "in") {
out = fromPx
@ -206,70 +202,53 @@ class FontInspector {
}
if (unit === "%") {
computedStyle =
await this.pageStyle.getComputed(referenceNode).catch(console.error);
if (!computedStyle) {
return value;
}
const fontSize = await this.getReferenceFontSize(property, unit);
out = fromPx
? value * 100 / parseFloat(computedStyle["font-size"].value)
: value / 100 * parseFloat(computedStyle["font-size"].value);
? value * 100 / parseFloat(fontSize)
: value / 100 * parseFloat(fontSize);
}
// Special handling for unitless line-height.
if (unit === "em" || (unit === "" && property === "line-height")) {
computedStyle =
await this.pageStyle.getComputed(referenceNode).catch(console.error);
if (!computedStyle) {
return value;
}
const fontSize = await this.getReferenceFontSize(property, unit);
out = fromPx
? value / parseFloat(computedStyle["font-size"].value)
: value * parseFloat(computedStyle["font-size"].value);
? value / parseFloat(fontSize)
: value * parseFloat(fontSize);
}
if (unit === "rem") {
const document = await this.inspector.walker.documentElement();
computedStyle = await this.pageStyle.getComputed(document).catch(console.error);
if (!computedStyle) {
return value;
}
const fontSize = await this.getReferenceFontSize(property, unit);
out = fromPx
? value / parseFloat(computedStyle["font-size"].value)
: value * parseFloat(computedStyle["font-size"].value);
? value / parseFloat(fontSize)
: value * parseFloat(fontSize);
}
if (unit === "vh" || unit === "vw" || unit === "vmin" || unit === "vmax") {
const dim = await node.getOwnerGlobalDimensions();
if (unit === "vh") {
const { height } = await this.getReferenceBox(property, unit);
out = fromPx
? value * 100 / height
: value / 100 * height;
}
// The getOwnerGlobalDimensions() method does not exist on the NodeFront API spec
// prior to Firefox 63. In that case, return a 1-to-1 conversion which isn't a
// correct conversion, but doesn't break the font editor either.
if (!dim || !dim.innerWidth || !dim.innerHeight) {
out = value;
} else if (unit === "vh") {
out = fromPx
? value * 100 / dim.innerHeight
: value / 100 * dim.innerHeight;
} else if (unit === "vw") {
out = fromPx
? value * 100 / dim.innerWidth
: value / 100 * dim.innerWidth;
} else if (unit === "vmin") {
out = fromPx
? value * 100 / Math.min(dim.innerWidth, dim.innerHeight)
: value / 100 * Math.min(dim.innerWidth, dim.innerHeight);
} else if (unit === "vmax") {
out = fromPx
? value * 100 / Math.max(dim.innerWidth, dim.innerHeight)
: value / 100 * Math.max(dim.innerWidth, dim.innerHeight);
}
if (unit === "vw") {
const { width } = await this.getReferenceBox(property, unit);
out = fromPx
? value * 100 / width
: value / 100 * width;
}
if (unit === "vmin") {
const { width, height } = await this.getReferenceBox(property, unit);
out = fromPx
? value * 100 / Math.min(width, height)
: value / 100 * Math.min(width, height);
}
if (unit === "vmax") {
const { width, height } = await this.getReferenceBox(property, unit);
out = fromPx
? value * 100 / Math.max(width, height)
: value / 100 * Math.max(width, height);
}
// Catch any NaN or Infinity as result of dividing by zero in any
@ -278,12 +257,15 @@ class FontInspector {
out = 0;
}
// Return rounded pixel values. Limit other values to 3 decimals.
if (fromPx) {
// Return values limited to 3 decimals when:
// - the unit is converted from pixels to something else
// - the value is for letter spacing, regardless of unit (allow sub-pixel precision)
if (fromPx || property === "letter-spacing") {
// Round values like 1.000 to 1
return out === Math.round(out) ? Math.round(out) : out.toFixed(3);
}
// Round pixel values.
return Math.round(out);
}
@ -360,6 +342,7 @@ class FontInspector {
* - font-size
* - font-weight
* - font-stretch
* - letter-spacing
* - line-height
*
* This list is used to filter out values when reading CSS font properties from rules.
@ -372,6 +355,7 @@ class FontInspector {
"font-size",
"font-weight",
"font-stretch",
"letter-spacing",
"line-height",
].reduce((acc, property) => {
return acc.concat(this.cssProperties.getValues(property));
@ -407,6 +391,109 @@ class FontInspector {
return allFonts;
}
/**
* Get the box dimensions used for unit conversion according to the CSS property and
* target CSS unit.
*
* @param {String} property
* CSS property
* @param {String} unit
* Target CSS unit
* @return {Promise}
* Promise that resolves with an object with box dimensions in pixels.
*/
async getReferenceBox(property, unit) {
const box = { width: 0, height: 0 };
const node = await this.getReferenceNode(property, unit).catch(console.error);
if (!node) {
return box;
}
switch (unit) {
case "vh":
case "vw":
case "vmin":
case "vmax":
const dim = await node.getOwnerGlobalDimensions().catch(console.error);
if (dim) {
box.width = dim.innerWidth;
box.height = dim.innerHeight;
}
break;
case "%":
const style = await this.pageStyle.getComputed(node).catch(console.error);
if (style) {
box.width = style.width.value;
box.height = style.height.value;
}
break;
}
return box;
}
/**
* Get the refernece font size value used for unit conversion according to the
* CSS property and target CSS unit.
*
* @param {String} property
* CSS property
* @param {String} unit
* Target CSS unit
* @return {Promise}
* Promise that resolves with the reference font size value or null if there
* was an error getting that value.
*/
async getReferenceFontSize(property, unit) {
const node = await this.getReferenceNode(property, unit).catch(console.error);
if (!node) {
return null;
}
const style = await this.pageStyle.getComputed(node).catch(console.error);
if (!style) {
return null;
}
return style["font-size"].value;
}
/**
* Get the reference node used in measurements for unit conversion according to the
* the CSS property and target CSS unit type.
*
* @param {String} property
* CSS property
* @param {String} unit
* Target CSS unit
* @return {Promise}
* Promise that resolves with the reference node used in measurements for unit
* conversion.
*/
async getReferenceNode(property, unit) {
let node;
switch (property) {
case "line-height":
case "letter-spacing":
node = this.node;
break;
default:
node = this.node.parentNode();
}
switch (unit) {
case "rem":
// Regardless of CSS property, always use the root document element for "rem".
node = await this.inspector.walker.documentElement();
break;
}
return node;
}
/**
* Get a reference to a TextProperty instance from the current selected rule for a
* given property name.

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

@ -22,8 +22,9 @@ subsuite = clipboard
[browser_fontinspector_all-fonts.js]
[browser_fontinspector_edit-previews.js]
[browser_fontinspector_editor-font-size-conversion.js]
[browser_fontinspector_editor-values.js]
[browser_fontinspector_editor-keywords.js]
[browser_fontinspector_editor-letter-spacing-conversion.js]
[browser_fontinspector_editor-values.js]
[browser_fontinspector_expand-css-code.js]
[browser_fontinspector_font-type-telemetry.js]
[browser_fontinspector_input-element-used-font.js]

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

@ -0,0 +1,58 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* global getPropertyValue */
"use strict";
// Unit test for math behind conversion of units for letter-spacing.
const TEST_URI = `
<style type='text/css'>
body {
/* Set root font-size to equivalent of 32px (2*16px) */
font-size: 200%;
}
div {
letter-spacing: 1em;
}
</style>
<div>LETTER SPACING</div>
`;
add_task(async function() {
const URI = "data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI);
const { inspector, view } = await openFontInspectorForURL(URI);
const viewDoc = view.document;
const property = "letter-spacing";
const UNITS = {
"px": 32,
"rem": 2,
"em": 1,
};
await selectNode("div", inspector);
info("Check that font editor shows letter-spacing value in original units");
const letterSpacing = getPropertyValue(viewDoc, property);
is(letterSpacing.value + letterSpacing.unit, "1em", "Original letter spacing is 1em");
// Starting value and unit for conversion.
let prevValue = letterSpacing.value;
let prevUnit = letterSpacing.unit;
for (const unit in UNITS) {
const value = UNITS[unit];
info(`Convert letter-spacing from ${prevValue}${prevUnit} to ${unit}`);
const convertedValue = await view.convertUnits(property, prevValue, prevUnit, unit);
is(convertedValue, value, `Converting to ${unit} returns transformed value.`);
// Store current unit and value to use in conversion on the next iteration.
prevUnit = unit;
prevValue = value;
}
info(`Check that conversion to fake unit returns 1-to-1 mapping`);
const valueToFakeUnit = await view.convertUnits(property, 1, "px", "fake");
is(valueToFakeUnit, 1, `Converting to fake unit returns same value.`);
});

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

@ -43,7 +43,7 @@ module.exports = {
* CSS unit type, like "px", "em", "rem", etc or null.
*/
getUnitFromValue(value) {
if (typeof value !== "string") {
if (typeof value !== "string" || isNaN(parseFloat(value))) {
return null;
}

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

@ -49,6 +49,10 @@ fontinspector.showMore=Show more
# LOCALIZATION NOTE (fontinspector.showLess): Label for an expanded list of fonts.
fontinspector.showLess=Show less
# LOCALIZATION NOTE (fontinspector.letterSpacingLabel): Label for the UI to change the
# letter spacing in the font editor.
fontinspector.letterSpacingLabel=Spacing
# LOCALIZATION NOTE (fontinspector.lineHeightLabelCapitalized): Label for the UI to change the line height in the font editor.
fontinspector.lineHeightLabelCapitalized=Line Height

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

@ -33,6 +33,7 @@
.network-monitor .custom-method-and-url input {
font-weight: 400;
margin-top: 4px;
min-width: 9ch;
padding: 2px 3px;
}
@ -58,28 +59,49 @@
}
.network-monitor .custom-request {
flex-direction: row-reverse;
flex-wrap: wrap;
display: block;
padding: 0;
}
.network-monitor .custom-request .custom-request-button-container {
display: flex;
flex-wrap: wrap-reverse;
margin-left: 12px;
}
.network-monitor .custom-request-panel .custom-request-label {
font-weight: 400;
white-space: nowrap;
}
.network-monitor .custom-request button {
align-self: flex-end;
height: 24px;
margin-bottom: 4px;
padding-left: 8px;
padding-right: 8px;
width: auto;
}
.network-monitor .custom-request button:focus {
box-shadow: 0 0 0 1px #0a84ff inset, 0 0 0 1px #0a84ff,
0 0 0 4px rgba(10,132,255,0.3)
}
.network-monitor .custom-request #custom-request-send-button {
background-color: var(--blue-60);
color: white;
margin-left: 4px;
margin-right: 16px;
}
.network-monitor .custom-request #custom-request-send-button:active {
background-color: var(--blue-80);
}
.network-monitor .custom-request #custom-request-send-button:hover {
background-color: var(--blue-70);
}
.network-monitor .custom-request #custom-request-close-button {
margin-right: 4px;
}
.network-monitor .custom-request .custom-header {
@ -101,6 +123,14 @@
border: 1px solid var(--theme-splitter-color);
}
:root.theme-dark .network-monitor #custom-request-close-button:hover:active {
background-color: var(--theme-selection-background-hover);
}
:root.theme-dark .network-monitor #custom-request-close-button:focus {
background-color: var(--theme-selection-focus-background);
}
:root.theme-dark .network-monitor .custom-request-label.custom-header {
background-color: var(--grey-80);
border-bottom: 1px solid var(--theme-splitter-color);
@ -124,6 +154,19 @@
:root.theme-light .network-monitor #custom-request-close-button {
background-color: var(--grey-20);
border: var(--theme-splitter-color);
}
:root.theme-light .network-monitor #custom-request-close-button:hover:active {
background-color: var(--theme-selection-background-hover);
}
:root.theme-light .network-monitor #custom-request-close-button:focus {
outline: 2px solid var(--blue-50);
outline-offset: -2px;
box-shadow: 0 0 0 2px rgba(10, 132, 255, 0.3);
border-radius: 2px;
-moz-outline-radius: 2px;
}
:root.theme-light .network-details-panel .custom-request-panel input,

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

@ -198,19 +198,21 @@ class CustomRequestPanel extends Component {
div({ className: "custom-request-label custom-header" },
CUSTOM_NEW_REQUEST,
),
button({
className: "devtools-button",
id: "custom-request-send-button",
onClick: sendCustomRequest,
},
CUSTOM_SEND,
),
button({
className: "devtools-button",
id: "custom-request-close-button",
onClick: removeSelectedCustomRequest,
},
CUSTOM_CANCEL,
div({ className: "custom-request-button-container" },
button({
className: "devtools-button",
id: "custom-request-close-button",
onClick: removeSelectedCustomRequest,
},
CUSTOM_CANCEL,
),
button({
className: "devtools-button",
id: "custom-request-send-button",
onClick: sendCustomRequest,
},
CUSTOM_SEND,
),
),
),
div({

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

@ -4,6 +4,7 @@
"use strict";
const { Component } = require("devtools/client/shared/vendor/react");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const { connect } = require("devtools/client/shared/redux/visibility-handler-connect");
@ -18,6 +19,7 @@ const {
getFormattedTime,
} = require("../utils/format-utils");
const { L10N } = require("../utils/l10n");
const { propertiesEqual } = require("../utils/request-utils");
const { button, div } = dom;
@ -30,23 +32,54 @@ const TOOLTIP_DOM_CONTENT_LOADED =
L10N.getStr("networkMenu.summary.tooltip.domContentLoaded");
const TOOLTIP_LOAD = L10N.getStr("networkMenu.summary.tooltip.load");
function StatusBar({ summary, openStatistics, timingMarkers }) {
const { count, contentSize, transferredSize, millis } = summary;
const {
DOMContentLoaded,
load,
} = timingMarkers;
const UPDATED_SUMMARY_PROPS = [
"count",
"contentSize",
"transferredSize",
"millis",
];
const countText = count === 0 ? REQUESTS_COUNT_EMPTY :
PluralForm.get(count,
L10N.getStr("networkMenu.summary.requestsCount2")).replace("#1", count);
const transferText = L10N.getFormatStrWithNumbers("networkMenu.summary.transferred",
getFormattedSize(contentSize), getFormattedSize(transferredSize));
const finishText = L10N.getFormatStrWithNumbers("networkMenu.summary.finish",
getFormattedTime(millis));
const UPDATED_TIMING_PROPS = [
"DOMContentLoaded",
"load",
];
return (
div({ className: "devtools-toolbar devtools-toolbar-bottom" },
/**
* Status Bar component
* Displays the summary of total size and transferred size by all requests
* Also displays different timing markers
*/
class StatusBar extends Component {
static get propTypes() {
return {
connector: PropTypes.object.isRequired,
openStatistics: PropTypes.func.isRequired,
summary: PropTypes.object.isRequired,
timingMarkers: PropTypes.object.isRequired,
};
}
shouldComponentUpdate(nextProps) {
const { summary, timingMarkers } = this.props;
return !propertiesEqual(UPDATED_SUMMARY_PROPS, summary, nextProps.summary) ||
!propertiesEqual(UPDATED_TIMING_PROPS, timingMarkers, nextProps.timingMarkers);
}
render() {
const { openStatistics, summary, timingMarkers } = this.props;
const { count, contentSize, transferredSize, millis } = summary;
const { DOMContentLoaded, load } = timingMarkers;
const countText = count === 0 ? REQUESTS_COUNT_EMPTY :
PluralForm.get(count,
L10N.getStr("networkMenu.summary.requestsCount2")).replace("#1", count);
const transferText = L10N.getFormatStrWithNumbers("networkMenu.summary.transferred",
getFormattedSize(contentSize), getFormattedSize(transferredSize));
const finishText = L10N.getFormatStrWithNumbers("networkMenu.summary.finish",
getFormattedTime(millis));
return (
div({ className: "devtools-toolbar devtools-toolbar-bottom" },
button({
className: "devtools-button requests-list-network-summary-button",
title: TOOLTIP_PERF,
@ -78,19 +111,11 @@ function StatusBar({ summary, openStatistics, timingMarkers }) {
className: "status-bar-label load",
title: TOOLTIP_LOAD,
}, `load: ${getFormattedTime(load)}`),
)
);
)
);
}
}
StatusBar.displayName = "StatusBar";
StatusBar.propTypes = {
connector: PropTypes.object.isRequired,
openStatistics: PropTypes.func.isRequired,
summary: PropTypes.object.isRequired,
timingMarkers: PropTypes.object.isRequired,
};
module.exports = connect(
(state) => ({
summary: getDisplayedRequestsSummary(state),

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

@ -751,8 +751,12 @@ module.exports = __webpack_require__(182);
const md5 = __webpack_require__(105);
function originalToGeneratedId(originalId) {
const match = originalId.match(/(.*)\/originalSource/);
function originalToGeneratedId(sourceId) {
if (isGeneratedId(sourceId)) {
return sourceId;
}
const match = sourceId.match(/(.*)\/originalSource/);
return match ? match[1] : "";
}

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

@ -13220,8 +13220,12 @@ module.exports = {
const md5 = __webpack_require__(105);
function originalToGeneratedId(originalId) {
const match = originalId.match(/(.*)\/originalSource/);
function originalToGeneratedId(sourceId) {
if (isGeneratedId(sourceId)) {
return sourceId;
}
const match = sourceId.match(/(.*)\/originalSource/);
return match ? match[1] : "";
}

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

@ -127,6 +127,7 @@
.font-family-name {
margin-bottom: 0.2em;
font-size: 1.2em;
padding: 0 3px;
}
.font-group {
@ -135,7 +136,12 @@
.font-group .font-name {
white-space: unset;
margin-right: .5em;
padding: 3px;
border-radius: 3px;
}
.font-group .font-name:hover {
background-color: var(--theme-selection-background-hover);
}
.font-group .font-name::after {
@ -285,6 +291,14 @@
border-right: none;
}
.font-value-label {
/* Combined width of .font-value-input and .font-value-select */
width: calc(60px + 3.8em);
margin-left: 10px;
padding-top: 2px;
padding-bottom: 4px;
}
/* Mock separator because inputs don't have distinguishable borders in dark theme */
.theme-dark .font-value-input + .font-value-select {
margin-left: 2px;

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

@ -264,10 +264,12 @@ class JSTerm extends Component {
"Left": onArrowLeft,
"Ctrl-Left": onArrowLeft,
"Cmd-Left": onArrowLeft,
"Alt-Left": onArrowLeft,
"Right": onArrowRight,
"Ctrl-Right": onArrowRight,
"Cmd-Right": onArrowRight,
"Alt-Right": onArrowRight,
"Ctrl-N": () => {
// Control-N differs from down arrow: it ignores autocomplete state.
@ -908,6 +910,7 @@ class JSTerm extends Component {
if (event.keyCode === KeyCodes.DOM_VK_RIGHT) {
if (this.getAutoCompletionText()) {
this.acceptProposedCompletion();
event.preventDefault();
}
this.clearCompletion();
event.preventDefault();

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

@ -11,7 +11,8 @@ const TEST_URI = `data:text/html;charset=utf-8,<head><script>
*/
window.foo = Object.create(null, Object.getOwnPropertyDescriptors({
aa: "a",
bb: "b",
bbb: "b",
bbbb: "b",
}));
</script></head><body>Autocomplete text navigation key usage test</body>`;
@ -29,70 +30,152 @@ async function performTests() {
const { jsterm } = hud;
const { autocompletePopup: popup } = jsterm;
const checkInput = (expected, assertionInfo) =>
checkInputValueAndCursorPosition(hud, expected, assertionInfo);
let onPopUpOpen = popup.once("popup-opened");
setInputValue(hud, "window.foo");
EventUtils.sendString(".");
await onPopUpOpen;
info("Trigger autocomplete popup opening");
// checkInput is asserting the cursor position with the "|" char.
checkInput("window.foo.|");
is(popup.isOpen, true, "popup is open");
checkInputCompletionValue(hud, " aa", "completeNode has expected value");
info("Test that arrow left closes the popup and clears complete node");
let onPopUpClose = popup.once("popup-closed");
EventUtils.synthesizeKey("KEY_ArrowLeft");
await onPopUpClose;
checkInput("window.foo|.");
is(popup.isOpen, false, "popup is closed");
checkInputCompletionValue(hud, "", "completeNode is empty");
info("Trigger autocomplete popup opening again");
onPopUpOpen = popup.once("popup-opened");
setInputValue(hud, "window.foo");
EventUtils.sendString(".");
await onPopUpOpen;
checkInput("window.foo.|");
is(popup.isOpen, true, "popup is open");
checkInputCompletionValue(hud, " aa", "completeNode has expected value");
info("Test that arrow right selects selected autocomplete item");
onPopUpClose = popup.once("popup-closed");
EventUtils.synthesizeKey("KEY_ArrowRight");
await onPopUpClose;
checkInput("window.foo.aa|");
is(popup.isOpen, false, "popup is closed");
checkInputCompletionValue(hud, "", "completeNode is empty");
info("Test that Ctrl/Cmd + Left removes complete node");
await setInputValueForAutocompletion(hud, "window.foo.a");
const prefix = getInputValue(hud).replace(/[\S]/g, " ");
checkInputCompletionValue(hud, prefix + "a", "completeNode has expected value");
const isOSX = Services.appinfo.OS == "Darwin";
EventUtils.synthesizeKey("KEY_ArrowLeft", {
[isOSX ? "metaKey" : "ctrlKey"]: true,
});
checkInputCompletionValue(hud, "",
"completeNode was cleared after Ctrl/Cmd + left");
await checkArrowLeftDismissPopup(hud);
await checkArrowLeftDismissCompletion(hud);
await checkArrowRightAcceptCompletion(hud);
info("Test that Ctrl/Cmd + Right closes the popup if there's text after cursor");
setInputValue(hud, ".");
EventUtils.synthesizeKey("KEY_ArrowLeft");
onPopUpOpen = popup.once("popup-opened");
const onPopUpOpen = popup.once("popup-opened");
EventUtils.sendString("win");
await onPopUpOpen;
ok(popup.isOpen, "popup is open");
onPopUpClose = popup.once("popup-closed");
const isOSX = Services.appinfo.OS == "Darwin";
const onPopUpClose = popup.once("popup-closed");
EventUtils.synthesizeKey("KEY_ArrowRight", {
[isOSX ? "metaKey" : "ctrlKey"]: true,
});
await onPopUpClose;
is(getInputValue(hud), "win.", "input value wasn't modified");
}
async function checkArrowLeftDismissPopup(hud) {
const popup = hud.jsterm.autocompletePopup;
let tests;
if (Services.appinfo.OS == "Darwin") {
tests = [{
keyOption: null,
expectedInput: "window.foo.b|b",
}, {
keyOption: {metaKey: true},
expectedInput: "|window.foo.bb",
}, {
keyOption: {altKey: true},
expectedInput: "window.foo.|bb",
}];
} else {
tests = [{
keyOption: null,
expectedInput: "window.foo.b|b",
}, {
keyOption: {ctrlKey: true},
expectedInput: "window.foo.|bb",
}];
}
for (const test of tests) {
info("Trigger autocomplete popup opening");
const onPopUpOpen = popup.once("popup-opened");
await setInputValueForAutocompletion(hud, "window.foo.bb");
await onPopUpOpen;
// checkInput is asserting the cursor position with the "|" char.
checkInputValueAndCursorPosition(hud, "window.foo.bb|");
is(popup.isOpen, true, "popup is open");
checkInputCompletionValue(hud, " b", "completeNode has expected value");
const {keyOption, expectedInput} = test;
info(`Test that arrow left closes the popup and clears complete node`);
const onPopUpClose = popup.once("popup-closed");
EventUtils.synthesizeKey("KEY_ArrowLeft", keyOption);
await onPopUpClose;
checkInputValueAndCursorPosition(hud, expectedInput);
is(popup.isOpen, false, "popup is closed");
checkInputCompletionValue(hud, "", "completeNode is empty");
}
setInputValue(hud, "");
}
async function checkArrowLeftDismissCompletion(hud) {
let tests;
if (Services.appinfo.OS == "Darwin") {
tests = [{
keyOption: null,
expectedInput: "window.foo.|a",
}, {
keyOption: {metaKey: true},
expectedInput: "|window.foo.a",
}, {
keyOption: {altKey: true},
expectedInput: "window.foo.|a",
}];
} else {
tests = [{
keyOption: null,
expectedInput: "window.foo.|a",
}, {
keyOption: {ctrlKey: true},
expectedInput: "window.foo.|a",
}];
}
for (const test of tests) {
await setInputValueForAutocompletion(hud, "window.foo.a");
const prefix = getInputValue(hud).replace(/[\S]/g, " ");
checkInputCompletionValue(hud, prefix + "a", "completeNode has expected value");
info(`Test that arrow left dismiss the completion text`);
const {keyOption, expectedInput} = test;
EventUtils.synthesizeKey("KEY_ArrowLeft", keyOption);
checkInputValueAndCursorPosition(hud, expectedInput);
checkInputCompletionValue(hud, "", "completeNode is empty");
}
setInputValue(hud, "");
}
async function checkArrowRightAcceptCompletion(hud) {
const popup = hud.jsterm.autocompletePopup;
let tests;
if (Services.appinfo.OS == "Darwin") {
tests = [{
keyOption: null,
}, {
keyOption: {metaKey: true},
}, {
keyOption: {altKey: true},
}];
} else {
tests = [{
keyOption: null,
}, {
keyOption: {ctrlKey: true},
}];
}
for (const test of tests) {
info("Trigger autocomplete popup opening");
const onPopUpOpen = popup.once("popup-opened");
await setInputValueForAutocompletion(hud, `window.foo.bb`);
await onPopUpOpen;
// checkInput is asserting the cursor position with the "|" char.
checkInputValueAndCursorPosition(hud, `window.foo.bb|`);
is(popup.isOpen, true, "popup is open");
checkInputCompletionValue(hud, " b", "completeNode has expected value");
const {keyOption} = test;
info(`Test that arrow right closes the popup and accepts the completion`);
const onPopUpClose = popup.once("popup-closed");
EventUtils.synthesizeKey("KEY_ArrowRight", keyOption);
await onPopUpClose;
checkInputValueAndCursorPosition(hud, "window.foo.bbb|");
is(popup.isOpen, false, "popup is closed");
checkInputCompletionValue(hud, "", "completeNode is empty");
}
setInputValue(hud, "");
}

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

@ -16,19 +16,18 @@ const BLOCKED_URL = TRACKER_URL +
"browser/devtools/client/webconsole/test/mochitest/test-image.png";
const {UrlClassifierTestUtils} = ChromeUtils.import("resource://testing-common/UrlClassifierTestUtils.jsm");
UrlClassifierTestUtils.addTestTrackers();
registerCleanupFunction(function() {
UrlClassifierTestUtils.cleanupTestTrackers();
});
pushPref("privacy.trackingprotection.enabled", true);
pushPref("devtools.webconsole.groupWarningMessages", true);
add_task(async function testContentBlockingMessage() {
const CONTENT_BLOCKING_GROUP_LABEL = "Content blocked messages";
// Tracking protection preferences
await UrlClassifierTestUtils.addTestTrackers();
await pushPref("privacy.trackingprotection.enabled", true);
// Enable groupWarning and persist log
await pushPref("devtools.webconsole.groupWarningMessages", true);
await pushPref("devtools.webconsole.persistlog", true);
const hud = await openNewTabAndConsole(TEST_URI);

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

@ -27,8 +27,8 @@
}
:-moz-native-anonymous .highlighter-container {
--highlighter-guide-color: #08c;
--highlighter-content-color: #87ceeb;
--highlighter-guide-color: hsl(200, 100%, 40%);
--highlighter-content-color: hsl(197, 71%, 73%);
--highlighter-bubble-text-color: hsl(216, 33%, 97%);
--highlighter-bubble-background-color: hsl(214, 13%, 24%);
--highlighter-bubble-border-color: rgba(255, 255, 255, 0.2);

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

@ -5,11 +5,21 @@
"use strict";
const InspectorUtils = require("InspectorUtils");
loader.lazyRequireGetter(this, "loadSheet", "devtools/shared/layout/utils", true);
loader.lazyRequireGetter(this, "removeSheet", "devtools/shared/layout/utils", true);
// How many text runs are we highlighting at a time. There may be many text runs, and we
// want to prevent performance problems.
const MAX_TEXT_RANGES = 100;
// This stylesheet is inserted into the page to customize the color of the selected text
// runs.
// Note that this color is defined as --highlighter-content-color in the highlighters.css
// file, and corresponds to the box-model content color. We want to give it an opacity of
// 0.6 here.
const STYLESHEET_URI = "data:text/css," +
encodeURIComponent("::selection{background-color:hsl(197,71%,73%,.6)!important;}");
/**
* This highlighter highlights runs of text in the page that have been rendered given a
* certain font. The highlighting is done with window selection ranges, so no extra
@ -61,6 +71,10 @@ class FontsHighlighter {
return;
}
// Load the stylesheet that will customize the color of the highlighter (using a
// ::selection rule).
loadSheet(this.env.window, STYLESHEET_URI);
// Create a multi-selection in the page to highlight the text runs.
const selection = doc.defaultView.getSelection();
selection.removeAllRanges();
@ -78,6 +92,12 @@ class FontsHighlighter {
return;
}
try {
removeSheet(this.env.window, STYLESHEET_URI);
} catch (e) {
// Silently fail here as we might not have inserted the stylesheet at all.
}
// Simply remove all current ranges in the seletion.
const doc = this.currentNodeDocument;
const selection = doc.defaultView.getSelection();

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

@ -136,7 +136,7 @@ struct GetOrInternStringMatcher {
explicit GetOrInternStringMatcher(InternedStringSet& strings)
: internedStrings(strings) {}
const CharT* match(const std::string* str) {
const CharT* operator()(const std::string* str) {
MOZ_ASSERT(str);
size_t length = str->length() / sizeof(CharT);
auto tempString = reinterpret_cast<const CharT*>(str->data());
@ -147,7 +147,7 @@ struct GetOrInternStringMatcher {
return internedStrings.back().get();
}
const CharT* match(uint64_t ref) {
const CharT* operator()(uint64_t ref) {
if (MOZ_LIKELY(ref < internedStrings.length())) {
auto& string = internedStrings[ref];
MOZ_ASSERT(string);
@ -787,37 +787,6 @@ class TwoByteString
: public Variant<JSAtom*, const char16_t*, JS::ubi::EdgeName> {
using Base = Variant<JSAtom*, const char16_t*, JS::ubi::EdgeName>;
struct AsTwoByteStringMatcher {
TwoByteString match(JSAtom* atom) { return TwoByteString(atom); }
TwoByteString match(const char16_t* chars) { return TwoByteString(chars); }
};
struct IsNonNullMatcher {
template <typename T>
bool match(const T& t) {
return t != nullptr;
}
};
struct LengthMatcher {
size_t match(JSAtom* atom) {
MOZ_ASSERT(atom);
JS::ubi::AtomOrTwoByteChars s(atom);
return s.length();
}
size_t match(const char16_t* chars) {
MOZ_ASSERT(chars);
return NS_strlen(chars);
}
size_t match(const JS::ubi::EdgeName& ptr) {
MOZ_ASSERT(ptr);
return NS_strlen(ptr.get());
}
};
struct CopyToBufferMatcher {
RangedPtr<char16_t> destination;
size_t maxLength;
@ -825,15 +794,17 @@ class TwoByteString
CopyToBufferMatcher(RangedPtr<char16_t> destination, size_t maxLength)
: destination(destination), maxLength(maxLength) {}
size_t match(JS::ubi::EdgeName& ptr) { return ptr ? match(ptr.get()) : 0; }
size_t operator()(JS::ubi::EdgeName& ptr) {
return ptr ? operator()(ptr.get()) : 0;
}
size_t match(JSAtom* atom) {
size_t operator()(JSAtom* atom) {
MOZ_ASSERT(atom);
JS::ubi::AtomOrTwoByteChars s(atom);
return s.copyToBuffer(destination, maxLength);
}
size_t match(const char16_t* chars) {
size_t operator()(const char16_t* chars) {
MOZ_ASSERT(chars);
JS::ubi::AtomOrTwoByteChars s(chars);
return s.copyToBuffer(destination, maxLength);
@ -857,20 +828,30 @@ class TwoByteString
// Rewrap the inner value of a JS::ubi::AtomOrTwoByteChars as a TwoByteString.
static TwoByteString from(JS::ubi::AtomOrTwoByteChars&& s) {
AsTwoByteStringMatcher m;
return s.match(m);
return s.match([](auto* a) { return TwoByteString(a); });
}
// Returns true if the given TwoByteString is non-null, false otherwise.
bool isNonNull() const {
IsNonNullMatcher m;
return match(m);
return match([](auto& t) { return t != nullptr; });
}
// Return the length of the string, 0 if it is null.
size_t length() const {
LengthMatcher m;
return match(m);
return match(
[](JSAtom* atom) -> size_t {
MOZ_ASSERT(atom);
JS::ubi::AtomOrTwoByteChars s(atom);
return s.length();
},
[](const char16_t* chars) -> size_t {
MOZ_ASSERT(chars);
return NS_strlen(chars);
},
[](const JS::ubi::EdgeName& ptr) -> size_t {
MOZ_ASSERT(ptr);
return NS_strlen(ptr.get());
});
}
// Copy the contents of a TwoByteString into the provided buffer. The buffer
@ -895,37 +876,33 @@ class TwoByteString
struct TwoByteString::HashPolicy {
using Lookup = TwoByteString;
struct HashingMatcher {
js::HashNumber match(const JSAtom* atom) {
return js::DefaultHasher<const JSAtom*>::hash(atom);
}
js::HashNumber match(const char16_t* chars) {
MOZ_ASSERT(chars);
auto length = NS_strlen(chars);
return HashString(chars, length);
}
js::HashNumber match(const JS::ubi::EdgeName& ptr) {
MOZ_ASSERT(ptr);
return match(ptr.get());
}
};
static js::HashNumber hash(const Lookup& l) {
HashingMatcher hasher;
return l.match(hasher);
return l.match(
[](const JSAtom* atom) {
return js::DefaultHasher<const JSAtom*>::hash(atom);
},
[](const char16_t* chars) {
MOZ_ASSERT(chars);
auto length = NS_strlen(chars);
return HashString(chars, length);
},
[](const JS::ubi::EdgeName& ptr) {
const char16_t* chars = ptr.get();
MOZ_ASSERT(chars);
auto length = NS_strlen(chars);
return HashString(chars, length);
});
}
struct EqualityMatcher {
const TwoByteString& rhs;
explicit EqualityMatcher(const TwoByteString& rhs) : rhs(rhs) {}
bool match(const JSAtom* atom) {
bool operator()(const JSAtom* atom) {
return rhs.is<JSAtom*>() && rhs.as<JSAtom*>() == atom;
}
bool match(const char16_t* chars) {
bool operator()(const char16_t* chars) {
MOZ_ASSERT(chars);
const char16_t* rhsChars = nullptr;
@ -943,9 +920,9 @@ struct TwoByteString::HashPolicy {
return memcmp(chars, rhsChars, length * sizeof(char16_t)) == 0;
}
bool match(const JS::ubi::EdgeName& ptr) {
bool operator()(const JS::ubi::EdgeName& ptr) {
MOZ_ASSERT(ptr);
return match(ptr.get());
return operator()(ptr.get());
}
};

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

@ -1868,6 +1868,7 @@ class Element : public FragmentOrElement {
/**
* Handle default actions for link event if the event isn't consumed yet.
*/
MOZ_CAN_RUN_SCRIPT
nsresult PostHandleEventForLinks(EventChainPostVisitor& aVisitor);
/**

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

@ -910,7 +910,8 @@ inline SelectionTypeMask ToSelectionTypeMask(SelectionType aSelectionType) {
MOZ_ASSERT(aSelectionType != SelectionType::eInvalid);
return aSelectionType == SelectionType::eNone
? 0
: (1 << (static_cast<uint8_t>(aSelectionType) - 1));
: static_cast<SelectionTypeMask>(
1 << (static_cast<uint8_t>(aSelectionType) - 1));
}
} // namespace mozilla

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

@ -162,7 +162,6 @@ DOM4_MSG_DEF(InvalidStateError, "XMLHttpRequest must not be sending.", NS_ERROR_
DOM4_MSG_DEF(InvalidStateError, "XMLHttpRequest state must not be LOADING or DONE.", NS_ERROR_DOM_INVALID_STATE_XHR_MUST_NOT_BE_LOADING_OR_DONE)
DOM4_MSG_DEF(InvalidStateError, "responseXML is only available if responseType is '' or 'document'.", NS_ERROR_DOM_INVALID_STATE_XHR_HAS_WRONG_RESPONSETYPE_FOR_RESPONSEXML)
DOM4_MSG_DEF(InvalidStateError, "responseText is only available if responseType is '' or 'text'.", NS_ERROR_DOM_INVALID_STATE_XHR_HAS_WRONG_RESPONSETYPE_FOR_RESPONSETEXT)
DOM4_MSG_DEF(InvalidStateError, "synchronous XMLHttpRequests do not support 'moz-chunked-arraybuffer' responseType.", NS_ERROR_DOM_INVALID_STATE_XHR_CHUNKED_RESPONSETYPES_UNSUPPORTED_FOR_SYNC)
DOM4_MSG_DEF(InvalidAccessError, "synchronous XMLHttpRequests do not support timeout and responseType.", NS_ERROR_DOM_INVALID_ACCESS_XHR_TIMEOUT_AND_RESPONSETYPE_UNSUPPORTED_FOR_SYNC)
/* Image decode errors. */

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

@ -948,6 +948,7 @@ class nsINode : public mozilla::dom::EventTarget {
mozilla::dom::CallerType aCallerType,
mozilla::ErrorResult& aRv) override;
MOZ_CAN_RUN_SCRIPT
nsresult PostHandleEvent(mozilla::EventChainPostVisitor& aVisitor) override;
/**

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

@ -55,32 +55,6 @@ self.onmessage = function onmessage(event) {
xhr.onloadend = null;
}
function test_chunked_arraybuffer() {
ok(true, "Test chunked arraybuffer");
var lastIndex = 0;
xhr.onprogress = function(event) {
if (xhr.response) {
var buf = new Uint8Array(xhr.response);
var allMatched = true;
// The content of data cycles from 0 to 9 (i.e. 01234567890123......).
for (var i = 0; i < buf.length; i++) {
if (String.fromCharCode(buf[i]) != lastIndex % 10) {
allMatched = false;
break;
}
lastIndex++;
}
ok(allMatched, "Data chunk is correct. Loaded " +
event.loaded + "/" + event.total + " bytes.");
}
};
xhr.onload = runTests;
xhr.open("GET", makeJarURL(gEntry3), true);
xhr.responseType = "moz-chunked-arraybuffer";
xhr.send();
}
var readystatechangeCount = 0;
var loadCount = 0;
var loadendCount = 0;
@ -152,7 +126,6 @@ self.onmessage = function onmessage(event) {
}
var tests = [
test_chunked_arraybuffer,
test_multiple_events,
test_sync_xhr_data1,
test_sync_xhr_data2,

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

@ -892,23 +892,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CanvasRenderingContext2D)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
CanvasRenderingContext2D::ContextState::ContextState()
: textAlign(TextAlign::START),
textBaseline(TextBaseline::ALPHABETIC),
shadowColor(0),
lineWidth(1.0f),
miterLimit(10.0f),
globalAlpha(1.0f),
shadowBlur(0.0),
dashOffset(0.0f),
op(mozilla::gfx::CompositionOp::OP_OVER),
fillRule(mozilla::gfx::FillRule::FILL_WINDING),
lineCap(mozilla::gfx::CapStyle::BUTT),
lineJoin(mozilla::gfx::JoinStyle::MITER_OR_BEVEL),
filterString(u"none"),
filterSourceGraphicTainted(false),
imageSmoothingEnabled(true),
fontExplicitLanguage(false) {}
CanvasRenderingContext2D::ContextState::ContextState() = default;
CanvasRenderingContext2D::ContextState::ContextState(const ContextState& aOther)
: fontGroup(aOther.fontGroup),

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

@ -945,26 +945,27 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
EnumeratedArray<Style, Style::MAX, nscolor> colorStyles;
nsString font;
TextAlign textAlign;
TextBaseline textBaseline;
TextAlign textAlign = TextAlign::START;
TextBaseline textBaseline = TextBaseline::ALPHABETIC;
nscolor shadowColor;
nscolor shadowColor = 0;
mozilla::gfx::Matrix transform;
mozilla::gfx::Point shadowOffset;
mozilla::gfx::Float lineWidth;
mozilla::gfx::Float miterLimit;
mozilla::gfx::Float globalAlpha;
mozilla::gfx::Float shadowBlur;
mozilla::gfx::Float lineWidth = 1.0f;
mozilla::gfx::Float miterLimit = 10.0f;
mozilla::gfx::Float globalAlpha = 1.0f;
mozilla::gfx::Float shadowBlur = 0.0f;
nsTArray<mozilla::gfx::Float> dash;
mozilla::gfx::Float dashOffset;
mozilla::gfx::Float dashOffset = 0.0f;
mozilla::gfx::CompositionOp op;
mozilla::gfx::FillRule fillRule;
mozilla::gfx::CapStyle lineCap;
mozilla::gfx::JoinStyle lineJoin;
mozilla::gfx::CompositionOp op = mozilla::gfx::CompositionOp::OP_OVER;
mozilla::gfx::FillRule fillRule = mozilla::gfx::FillRule::FILL_WINDING;
mozilla::gfx::CapStyle lineCap = mozilla::gfx::CapStyle::BUTT;
mozilla::gfx::JoinStyle lineJoin = mozilla::gfx::JoinStyle::MITER_OR_BEVEL;
nsString filterString;
nsString filterString = nsString(u"none");
nsTArray<nsStyleFilter> filterChain;
// RAII object that we obtain when we start to observer SVG filter elements
// for rendering changes. When released we stop observing the SVG elements.
@ -983,10 +984,10 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
//
// We keep track of this to ensure that if this gets out of sync with the
// tainted state of the canvas itself, we update our filters accordingly.
bool filterSourceGraphicTainted;
bool filterSourceGraphicTainted = false;
bool imageSmoothingEnabled;
bool fontExplicitLanguage;
bool imageSmoothingEnabled = true;
bool fontExplicitLanguage = false;
};
AutoTArray<ContextState, 3> mStyleStack;

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

@ -19,9 +19,9 @@ static __inline int32_t clamp255(int32_t v) {
return (((255 - (v)) >> 31) | (v)) & 255;
}
static __inline uint32_t Clamp(int32_t val) {
int v = clamp0(val);
return (uint32_t)(clamp255(v));
static __inline uint8_t Clamp(int32_t val) {
const auto v = clamp0(val);
return uint8_t(clamp255(v));
}
#define YG 74 /* (int8_t)(1.164 * 64 + 0.5) */
@ -47,16 +47,16 @@ static __inline void YuvPixel(uint8_t y, uint8_t u, uint8_t v, uint8_t* b,
*r = Clamp((int32_t)((u * UR + v * VR) - (BR) + y1) >> 6);
}
static __inline int RGBToY(uint8_t r, uint8_t g, uint8_t b) {
return (66 * r + 129 * g + 25 * b + 0x1080) >> 8;
static __inline uint8_t RGBToY(uint8_t r, uint8_t g, uint8_t b) {
return uint8_t((66 * r + 129 * g + 25 * b + 0x1080) >> 8);
}
static __inline int RGBToU(uint8_t r, uint8_t g, uint8_t b) {
return (112 * b - 74 * g - 38 * r + 0x8080) >> 8;
static __inline uint8_t RGBToU(uint8_t r, uint8_t g, uint8_t b) {
return uint8_t((112 * b - 74 * g - 38 * r + 0x8080) >> 8);
}
static __inline int RGBToV(uint8_t r, uint8_t g, uint8_t b) {
return (112 * r - 94 * g - 18 * b + 0x8080) >> 8;
static __inline uint8_t RGBToV(uint8_t r, uint8_t g, uint8_t b) {
return uint8_t((112 * r - 94 * g - 18 * b + 0x8080) >> 8);
}
/*

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

@ -191,7 +191,7 @@ class Utils {
uint8_t GetChannelCount() const { return mChannels; }
protected:
Utils(uint32_t aChannels, ChannelPixelLayoutDataType aDataType)
Utils(uint8_t aChannels, ChannelPixelLayoutDataType aDataType)
: mChannels(aChannels),
mBytesPerPixelValue(GetBytesPerPixelValue(aDataType)),
mDataType(aDataType) {}

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

@ -128,7 +128,7 @@ WebGLContext::WebGLContext()
mNeedsFakeNoDepth(false),
mNeedsFakeNoStencil(false),
mAllowFBInvalidation(gfxPrefs::WebGLFBInvalidation()),
mMsaaSamples(gfxPrefs::WebGLMsaaSamples()) {
mMsaaSamples((uint8_t)gfxPrefs::WebGLMsaaSamples()) {
mGeneration = 0;
mInvalidated = false;
mCapturedFrameInvalidated = false;

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

@ -112,8 +112,8 @@ void WebGLContext::ColorMask(WebGLboolean r, WebGLboolean g, WebGLboolean b,
const FuncScope funcScope(*this, "colorMask");
if (IsContextLost()) return;
mColorWriteMask = uint8_t(bool(r)) << 0 | uint8_t(bool(g)) << 1 |
uint8_t(bool(b)) << 2 | uint8_t(bool(a)) << 3;
mColorWriteMask = uint8_t(bool(r) << 0) | uint8_t(bool(g) << 1) |
uint8_t(bool(b) << 2) | uint8_t(bool(a) << 3);
}
void WebGLContext::DepthMask(WebGLboolean b) {

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

@ -6,6 +6,7 @@
#include "WebGLContext.h"
#include "GLContext.h"
#include "mozilla/Casting.h"
#include "mozilla/CheckedInt.h"
#include "WebGLBuffer.h"
#include "WebGLFramebuffer.h"
@ -401,7 +402,7 @@ void WebGLContext::VertexAttribAnyPointer(bool isFuncInt, GLuint index,
}
WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[index];
vd.VertexAttribPointer(isFuncInt, buffer, size, type, normalized, stride,
vd.VertexAttribPointer(isFuncInt, buffer, AutoAssertCast(size), type, normalized, stride,
byteOffset);
mBoundVertexArray->InvalidateCaches();
}

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

@ -521,9 +521,9 @@ MOZ_ALWAYS_INLINE void unpack<WebGLTexelFormat::RGB565, uint16_t, uint8_t>(
uint8_t r = (packedValue >> 11) & 0x1F;
uint8_t g = (packedValue >> 5) & 0x3F;
uint8_t b = packedValue & 0x1F;
dst[0] = (r << 3) | (r & 0x7);
dst[1] = (g << 2) | (g & 0x3);
dst[2] = (b << 3) | (b & 0x7);
dst[0] = uint8_t(r << 3) | (r & 0x7);
dst[1] = uint8_t(g << 2) | (g & 0x3);
dst[2] = uint8_t(b << 3) | (b & 0x7);
dst[3] = 0xFF;
}
@ -564,10 +564,10 @@ MOZ_ALWAYS_INLINE void unpack<WebGLTexelFormat::RGBA4444, uint16_t, uint8_t>(
uint8_t g = (packedValue >> 8) & 0x0F;
uint8_t b = (packedValue >> 4) & 0x0F;
uint8_t a = packedValue & 0x0F;
dst[0] = (r << 4) | r;
dst[1] = (g << 4) | g;
dst[2] = (b << 4) | b;
dst[3] = (a << 4) | a;
dst[0] = uint8_t(r << 4) | r;
dst[1] = uint8_t(g << 4) | g;
dst[2] = uint8_t(b << 4) | b;
dst[3] = uint8_t(a << 4) | a;
}
template <>
@ -577,9 +577,9 @@ MOZ_ALWAYS_INLINE void unpack<WebGLTexelFormat::RGBA5551, uint16_t, uint8_t>(
uint8_t r = (packedValue >> 11) & 0x1F;
uint8_t g = (packedValue >> 6) & 0x1F;
uint8_t b = (packedValue >> 1) & 0x1F;
dst[0] = (r << 3) | (r & 0x7);
dst[1] = (g << 3) | (g & 0x7);
dst[2] = (b << 3) | (b & 0x7);
dst[0] = uint8_t(r << 3) | (r & 0x7);
dst[1] = uint8_t(g << 3) | (g & 0x7);
dst[2] = uint8_t(b << 3) | (b & 0x7);
dst[3] = (packedValue & 0x1) ? 0xFF : 0;
}
@ -961,7 +961,7 @@ template <>
MOZ_ALWAYS_INLINE void
pack<WebGLTexelFormat::RGB565, WebGLTexelPremultiplicationOp::None, uint8_t,
uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst) {
*dst = (((src[0] & 0xF8) << 8) | ((src[1] & 0xFC) << 3) |
*dst = uint16_t(((src[0] & 0xF8) << 8) | ((src[1] & 0xFC) << 3) |
((src[2] & 0xF8) >> 3));
}
@ -974,7 +974,7 @@ pack<WebGLTexelFormat::RGB565, WebGLTexelPremultiplicationOp::Premultiply,
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
uint8_t srcG = static_cast<uint8_t>(src[1] * scaleFactor);
uint8_t srcB = static_cast<uint8_t>(src[2] * scaleFactor);
*dst = (((srcR & 0xF8) << 8) | ((srcG & 0xFC) << 3) | ((srcB & 0xF8) >> 3));
*dst = uint16_t(((srcR & 0xF8) << 8) | ((srcG & 0xFC) << 3) | ((srcB & 0xF8) >> 3));
}
// FIXME: this routine is lossy and must be removed.
@ -987,7 +987,7 @@ pack<WebGLTexelFormat::RGB565, WebGLTexelPremultiplicationOp::Unpremultiply,
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
uint8_t srcG = static_cast<uint8_t>(src[1] * scaleFactor);
uint8_t srcB = static_cast<uint8_t>(src[2] * scaleFactor);
*dst = (((srcR & 0xF8) << 8) | ((srcG & 0xFC) << 3) | ((srcB & 0xF8) >> 3));
*dst = uint16_t(((srcR & 0xF8) << 8) | ((srcG & 0xFC) << 3) | ((srcB & 0xF8) >> 3));
}
template <>
@ -1121,7 +1121,7 @@ template <>
MOZ_ALWAYS_INLINE void
pack<WebGLTexelFormat::RGBA4444, WebGLTexelPremultiplicationOp::None, uint8_t,
uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst) {
*dst = (((src[0] & 0xF0) << 8) | ((src[1] & 0xF0) << 4) | (src[2] & 0xF0) |
*dst = uint16_t(((src[0] & 0xF0) << 8) | ((src[1] & 0xF0) << 4) | (src[2] & 0xF0) |
(src[3] >> 4));
}
@ -1134,7 +1134,7 @@ pack<WebGLTexelFormat::RGBA4444, WebGLTexelPremultiplicationOp::Premultiply,
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
uint8_t srcG = static_cast<uint8_t>(src[1] * scaleFactor);
uint8_t srcB = static_cast<uint8_t>(src[2] * scaleFactor);
*dst = (((srcR & 0xF0) << 8) | ((srcG & 0xF0) << 4) | (srcB & 0xF0) |
*dst = uint16_t(((srcR & 0xF0) << 8) | ((srcG & 0xF0) << 4) | (srcB & 0xF0) |
(src[3] >> 4));
}
@ -1148,7 +1148,7 @@ pack<WebGLTexelFormat::RGBA4444, WebGLTexelPremultiplicationOp::Unpremultiply,
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
uint8_t srcG = static_cast<uint8_t>(src[1] * scaleFactor);
uint8_t srcB = static_cast<uint8_t>(src[2] * scaleFactor);
*dst = (((srcR & 0xF0) << 8) | ((srcG & 0xF0) << 4) | (srcB & 0xF0) |
*dst = uint16_t(((srcR & 0xF0) << 8) | ((srcG & 0xF0) << 4) | (srcB & 0xF0) |
(src[3] >> 4));
}
@ -1156,7 +1156,7 @@ template <>
MOZ_ALWAYS_INLINE void
pack<WebGLTexelFormat::RGBA5551, WebGLTexelPremultiplicationOp::None, uint8_t,
uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst) {
*dst = (((src[0] & 0xF8) << 8) | ((src[1] & 0xF8) << 3) |
*dst = uint16_t(((src[0] & 0xF8) << 8) | ((src[1] & 0xF8) << 3) |
((src[2] & 0xF8) >> 2) | (src[3] >> 7));
}
@ -1169,7 +1169,7 @@ pack<WebGLTexelFormat::RGBA5551, WebGLTexelPremultiplicationOp::Premultiply,
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
uint8_t srcG = static_cast<uint8_t>(src[1] * scaleFactor);
uint8_t srcB = static_cast<uint8_t>(src[2] * scaleFactor);
*dst = (((srcR & 0xF8) << 8) | ((srcG & 0xF8) << 3) | ((srcB & 0xF8) >> 2) |
*dst = uint16_t(((srcR & 0xF8) << 8) | ((srcG & 0xF8) << 3) | ((srcB & 0xF8) >> 2) |
(src[3] >> 7));
}
@ -1183,7 +1183,7 @@ pack<WebGLTexelFormat::RGBA5551, WebGLTexelPremultiplicationOp::Unpremultiply,
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
uint8_t srcG = static_cast<uint8_t>(src[1] * scaleFactor);
uint8_t srcB = static_cast<uint8_t>(src[2] * scaleFactor);
*dst = (((srcR & 0xF8) << 8) | ((srcG & 0xF8) << 3) | ((srcB & 0xF8) >> 2) |
*dst = uint16_t(((srcR & 0xF8) << 8) | ((srcG & 0xF8) << 3) | ((srcB & 0xF8) >> 2) |
(src[3] >> 7));
}

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

@ -7,6 +7,7 @@
#include <algorithm>
#include "GLContext.h"
#include "mozilla/Casting.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/MathAlgorithms.h"
@ -260,7 +261,7 @@ Maybe<const WebGLTexture::CompletenessInfo> WebGLTexture::CalcCompletenessInfo(
ret->incompleteReason = "Bad mipmap dimension or format.";
return ret;
}
ret->levels = maxLevel - mBaseMipmapLevel + 1;
ret->levels = AutoAssertCast(maxLevel - mBaseMipmapLevel + 1);
ret->mipmapComplete = true;
// -

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

@ -12,6 +12,7 @@
#include <vector>
#include "mozilla/Assertions.h"
#include "mozilla/Casting.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/dom/TypedArray.h"
#include "mozilla/LinkedList.h"
@ -269,7 +270,7 @@ class WebGLTexture final : public nsWrapperCache,
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
return rawTexImageTarget - LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
return AutoAssertCast(rawTexImageTarget - LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X);
default:
return 0;

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

@ -11,6 +11,7 @@
#include "gfxPrefs.h"
#include "GLBlitHelper.h"
#include "GLContext.h"
#include "mozilla/Casting.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/dom/HTMLCanvasElement.h"
#include "mozilla/dom/HTMLVideoElement.h"
@ -1124,7 +1125,7 @@ void WebGLTexture::TexStorage(TexTarget target, GLsizei levels,
}
mImmutable = true;
mImmutableLevelCount = levels;
mImmutableLevelCount = AutoAssertCast(levels);
ClampLevelBaseAndMax();
}

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

@ -10,6 +10,7 @@
// Most WebIDL typedefs are identical to their OpenGL counterparts.
#include "GLTypes.h"
#include "mozilla/Casting.h"
// Manual reflection of WebIDL typedefs that are different from their
// OpenGL counterparts.
@ -55,6 +56,30 @@ inline void* calloc(const ForbidNarrowing<size_t> n,
return ::calloc(size_t(n), size_t(size));
}
// -
namespace detail {
template<typename From>
class AutoAssertCastT final {
const From mVal;
public:
explicit AutoAssertCastT(const From val) : mVal(val) { }
template<typename To>
operator To() const {
return AssertedCast<To>(mVal);
}
};
} // namespace detail
template<typename From>
inline auto AutoAssertCast(const From val) {
return detail::AutoAssertCastT<From>(val);
}
/*
* Implementing WebGL (or OpenGL ES 2.0) on top of desktop OpenGL requires
* emulating the vertex attrib 0 array when it's not enabled. Indeed,

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

@ -217,3 +217,6 @@ LOCAL_INCLUDES += CONFIG['SKIA_INCLUDES']
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CXXFLAGS += ['-Wno-error=shadow', '-Wno-missing-braces']
if CONFIG['CC_TYPE'] in ('clang', 'clang-cl'):
CXXFLAGS += ['-Werror=implicit-int-conversion']

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

@ -128,11 +128,9 @@ static bool IsEventTargetChrome(EventTarget* aEventTarget,
// EventTargetChainItem represents a single item in the event target chain.
class EventTargetChainItem {
private:
explicit EventTargetChainItem(EventTarget* aTarget);
public:
EventTargetChainItem() : mItemFlags(0) {
explicit EventTargetChainItem(EventTarget* aTarget)
: mTarget(aTarget), mItemFlags(0) {
MOZ_COUNT_CTOR(EventTargetChainItem);
}
@ -144,8 +142,7 @@ class EventTargetChainItem {
// The last item which can handle the event must be aChild.
MOZ_ASSERT(GetLastCanHandleEventTarget(aChain) == aChild);
MOZ_ASSERT(!aTarget || aTarget == aTarget->GetTargetForEventTargetChain());
EventTargetChainItem* etci = aChain.AppendElement();
etci->mTarget = aTarget;
EventTargetChainItem* etci = aChain.AppendElement(aTarget);
return etci;
}
@ -304,6 +301,7 @@ class EventTargetChainItem {
* and system event group and calls also PostHandleEvent for each
* item in the chain.
*/
MOZ_CAN_RUN_SCRIPT
static void HandleEventTargetChain(nsTArray<EventTargetChainItem>& aChain,
EventChainPostVisitor& aVisitor,
EventDispatchingCallback* aCallback,
@ -359,10 +357,10 @@ class EventTargetChainItem {
/**
* Copies mItemFlags and mItemData to aVisitor and calls PostHandleEvent.
*/
void PostHandleEvent(EventChainPostVisitor& aVisitor);
MOZ_CAN_RUN_SCRIPT void PostHandleEvent(EventChainPostVisitor& aVisitor);
private:
nsCOMPtr<EventTarget> mTarget;
const nsCOMPtr<EventTarget> mTarget;
nsCOMPtr<EventTarget> mRetargetedRelatedTarget;
Maybe<nsTArray<RefPtr<EventTarget>>> mRetargetedTouchTargets;
Maybe<nsTArray<RefPtr<dom::Touch>>> mInitialTargetTouches;

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

@ -332,6 +332,9 @@ class EventDispatcher {
* eVoidEvent.
* @note Use this method when dispatching a WidgetEvent.
*/
// This should obviously be MOZ_CAN_RUN_SCRIPT, but that's a bit of
// a project. See bug 1539884.
MOZ_CAN_RUN_SCRIPT_BOUNDARY
static nsresult Dispatch(nsISupports* aTarget, nsPresContext* aPresContext,
WidgetEvent* aEvent, dom::Event* aDOMEvent = nullptr,
nsEventStatus* aEventStatus = nullptr,

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

@ -248,6 +248,7 @@ class EventTarget : public nsISupports, public nsWrapperCache {
* @see EventDispatcher.h for documentation about aVisitor.
* @note Only EventDispatcher should call this method.
*/
MOZ_CAN_RUN_SCRIPT
virtual nsresult PostHandleEvent(EventChainPostVisitor& aVisitor) = 0;
protected:

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

@ -51,7 +51,8 @@ class HTMLAnchorElement final : public nsGenericHTMLElement, public Link {
int32_t* aTabIndex) override;
void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
virtual nsresult PostHandleEvent(EventChainPostVisitor& aVisitor) override;
MOZ_CAN_RUN_SCRIPT
nsresult PostHandleEvent(EventChainPostVisitor& aVisitor) override;
virtual bool IsLink(nsIURI** aURI) const override;
virtual void GetLinkTarget(nsAString& aTarget) override;
virtual already_AddRefed<nsIURI> GetHrefURI() const override;

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

@ -37,7 +37,8 @@ class HTMLAreaElement final : public nsGenericHTMLElement, public Link {
virtual int32_t TabIndexDefault() override;
void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
virtual nsresult PostHandleEvent(EventChainPostVisitor& aVisitor) override;
MOZ_CAN_RUN_SCRIPT
nsresult PostHandleEvent(EventChainPostVisitor& aVisitor) override;
virtual bool IsLink(nsIURI** aURI) const override;
virtual void GetLinkTarget(nsAString& aTarget) override;
virtual already_AddRefed<nsIURI> GetHrefURI() const override;

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

@ -39,7 +39,8 @@ class HTMLLinkElement final : public nsGenericHTMLElement,
// EventTarget
void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
virtual nsresult PostHandleEvent(EventChainPostVisitor& aVisitor) override;
MOZ_CAN_RUN_SCRIPT
nsresult PostHandleEvent(EventChainPostVisitor& aVisitor) override;
// nsINode
virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;

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

@ -196,7 +196,8 @@ class HTMLSelectElement final : public nsGenericHTMLFormElementWithState,
// nsIContent
void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
virtual nsresult PostHandleEvent(EventChainPostVisitor& aVisitor) override;
MOZ_CAN_RUN_SCRIPT
nsresult PostHandleEvent(EventChainPostVisitor& aVisitor) override;
virtual bool IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
int32_t* aTabIndex) override;

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

@ -267,6 +267,7 @@ class nsGenericHTMLElement : public nsGenericHTMLElementBase {
bool CheckHandleEventForAnchorsPreconditions(
mozilla::EventChainVisitor& aVisitor);
void GetEventTargetParentForAnchors(mozilla::EventChainPreVisitor& aVisitor);
MOZ_CAN_RUN_SCRIPT
nsresult PostHandleEventForAnchors(mozilla::EventChainPostVisitor& aVisitor);
bool IsHTMLLink(nsIURI** aURI) const;

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

@ -7259,22 +7259,22 @@ void ArchivedOriginScope::GetBindingClause(nsACString& aBindingClause) const {
explicit Matcher(nsACString* aBindingClause)
: mBindingClause(aBindingClause) {}
void match(const Origin& aOrigin) {
void operator()(const Origin& aOrigin) {
*mBindingClause = NS_LITERAL_CSTRING(
" WHERE originKey = :originKey "
"AND originAttributes = :originAttributes");
}
void match(const Prefix& aPrefix) {
void operator()(const Prefix& aPrefix) {
*mBindingClause = NS_LITERAL_CSTRING(" WHERE originKey = :originKey");
}
void match(const Pattern& aPattern) {
void operator()(const Pattern& aPattern) {
*mBindingClause = NS_LITERAL_CSTRING(
" WHERE originAttributes MATCH :originAttributesPattern");
}
void match(const Null& aNull) { *mBindingClause = EmptyCString(); }
void operator()(const Null& aNull) { *mBindingClause = EmptyCString(); }
};
mData.match(Matcher(&aBindingClause));
@ -7290,7 +7290,7 @@ nsresult ArchivedOriginScope::BindToStatement(
explicit Matcher(mozIStorageStatement* aStmt) : mStmt(aStmt) {}
nsresult match(const Origin& aOrigin) {
nsresult operator()(const Origin& aOrigin) {
nsresult rv = mStmt->BindUTF8StringByName(NS_LITERAL_CSTRING("originKey"),
aOrigin.OriginNoSuffix());
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -7306,7 +7306,7 @@ nsresult ArchivedOriginScope::BindToStatement(
return NS_OK;
}
nsresult match(const Prefix& aPrefix) {
nsresult operator()(const Prefix& aPrefix) {
nsresult rv = mStmt->BindUTF8StringByName(NS_LITERAL_CSTRING("originKey"),
aPrefix.OriginNoSuffix());
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -7316,7 +7316,7 @@ nsresult ArchivedOriginScope::BindToStatement(
return NS_OK;
}
nsresult match(const Pattern& aPattern) {
nsresult operator()(const Pattern& aPattern) {
nsresult rv = mStmt->BindUTF8StringByName(
NS_LITERAL_CSTRING("originAttributesPattern"),
NS_LITERAL_CSTRING("pattern1"));
@ -7327,7 +7327,7 @@ nsresult ArchivedOriginScope::BindToStatement(
return NS_OK;
}
nsresult match(const Null& aNull) { return NS_OK; }
nsresult operator()(const Null& aNull) { return NS_OK; }
};
nsresult rv = mData.match(Matcher(aStmt));
@ -7349,7 +7349,7 @@ bool ArchivedOriginScope::HasMatches(
explicit Matcher(ArchivedOriginHashtable* aHashtable)
: mHashtable(aHashtable) {}
bool match(const Origin& aOrigin) {
bool operator()(const Origin& aOrigin) {
nsCString hashKey = GetArchivedOriginHashKey(aOrigin.OriginSuffix(),
aOrigin.OriginNoSuffix());
@ -7357,7 +7357,7 @@ bool ArchivedOriginScope::HasMatches(
return mHashtable->Get(hashKey, &archivedOriginInfo);
}
bool match(const Prefix& aPrefix) {
bool operator()(const Prefix& aPrefix) {
for (auto iter = mHashtable->ConstIter(); !iter.Done(); iter.Next()) {
ArchivedOriginInfo* archivedOriginInfo = iter.Data();
@ -7369,7 +7369,7 @@ bool ArchivedOriginScope::HasMatches(
return false;
}
bool match(const Pattern& aPattern) {
bool operator()(const Pattern& aPattern) {
for (auto iter = mHashtable->ConstIter(); !iter.Done(); iter.Next()) {
ArchivedOriginInfo* archivedOriginInfo = iter.Data();
@ -7382,7 +7382,7 @@ bool ArchivedOriginScope::HasMatches(
return false;
}
bool match(const Null& aNull) { return mHashtable->Count(); }
bool operator()(const Null& aNull) { return mHashtable->Count(); }
};
return mData.match(Matcher(aHashtable));
@ -7399,14 +7399,14 @@ void ArchivedOriginScope::RemoveMatches(
explicit Matcher(ArchivedOriginHashtable* aHashtable)
: mHashtable(aHashtable) {}
void match(const Origin& aOrigin) {
void operator()(const Origin& aOrigin) {
nsCString hashKey = GetArchivedOriginHashKey(aOrigin.OriginSuffix(),
aOrigin.OriginNoSuffix());
mHashtable->Remove(hashKey);
}
void match(const Prefix& aPrefix) {
void operator()(const Prefix& aPrefix) {
for (auto iter = mHashtable->Iter(); !iter.Done(); iter.Next()) {
ArchivedOriginInfo* archivedOriginInfo = iter.Data();
@ -7416,7 +7416,7 @@ void ArchivedOriginScope::RemoveMatches(
}
}
void match(const Pattern& aPattern) {
void operator()(const Pattern& aPattern) {
for (auto iter = mHashtable->Iter(); !iter.Done(); iter.Next()) {
ArchivedOriginInfo* archivedOriginInfo = iter.Data();
@ -7427,7 +7427,7 @@ void ArchivedOriginScope::RemoveMatches(
}
}
void match(const Null& aNull) { mHashtable->Clear(); }
void operator()(const Null& aNull) { mHashtable->Clear(); }
};
mData.match(Matcher(aHashtable));

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