зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-inbound to mozilla-central. a=merge
This commit is contained in:
Коммит
14dc5b7d8a
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче