Merge mozilla-central to mozilla-inbound

This commit is contained in:
arthur.iakab 2019-06-01 01:30:47 +03:00
Родитель 3d92be0a81 63db2e3489
Коммит 36d75a7e56
184 изменённых файлов: 4941 добавлений и 3334 удалений

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

@ -348,11 +348,11 @@ bool TextAttrsMgr::BGColorTextAttr::GetColor(nsIFrame* aFrame,
TextAttrsMgr::ColorTextAttr::ColorTextAttr(nsIFrame* aRootFrame,
nsIFrame* aFrame)
: TTextAttr<nscolor>(!aFrame) {
mRootNativeValue = aRootFrame->StyleColor()->mColor.ToColor();
mRootNativeValue = aRootFrame->StyleText()->mColor.ToColor();
mIsRootDefined = true;
if (aFrame) {
mNativeValue = aFrame->StyleColor()->mColor.ToColor();
mNativeValue = aFrame->StyleText()->mColor.ToColor();
mIsDefined = true;
}
}
@ -362,7 +362,7 @@ bool TextAttrsMgr::ColorTextAttr::GetValueFor(Accessible* aAccessible,
nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
if (elm) {
if (nsIFrame* frame = elm->GetPrimaryFrame()) {
*aValue = frame->StyleColor()->mColor.ToColor();
*aValue = frame->StyleText()->mColor.ToColor();
return true;
}
}

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

@ -79,7 +79,7 @@ ia2AccessibleComponent::get_foreground(IA2Color* aForeground) {
if (acc->IsDefunct()) return CO_E_OBJNOTCONNECTED;
nsIFrame* frame = acc->GetFrame();
if (frame) *aForeground = frame->StyleColor()->mColor.ToColor();
if (frame) *aForeground = frame->StyleText()->mColor.ToColor();
return S_OK;
}

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

@ -1046,7 +1046,7 @@ browser[tabmodalPromptShowing] {
and just show the icon. This is a hack to side-step very weird layout bugs that
seem to be caused by the indicator stack interacting with the menu panel. */
#downloads-button[indicator]:not([cui-areatype="menu-panel"]) > .toolbarbutton-badge-stack > image.toolbarbutton-icon,
#downloads-button[indicator][cui-areatype="menu-panel"] > #downloads-indicator-anchor {
#downloads-button[indicator][cui-areatype="menu-panel"] > .toolbarbutton-badge-stack > #downloads-indicator-anchor {
display: none;
}
@ -1054,7 +1054,7 @@ toolbarpaletteitem[place="palette"] > #downloads-button[indicator] > .toolbarbut
display: -moz-box;
}
toolbarpaletteitem[place="palette"] > #downloads-button[indicator] > #downloads-indicator-anchor {
toolbarpaletteitem[place="palette"] > #downloads-button[indicator] > .toolbarbutton-badge-stack > #downloads-indicator-anchor {
display: none;
}

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

@ -11,171 +11,15 @@ class MozTabbrowserTab extends MozElements.MozTab {
constructor() {
super();
this.addEventListener("mouseover", (event) => {
if (event.originalTarget.classList.contains("tab-close-button")) {
this.mOverCloseButton = true;
}
this._mouseenter();
});
this.addEventListener("mouseout", (event) => {
if (event.originalTarget.classList.contains("tab-close-button")) {
this.mOverCloseButton = false;
}
this._mouseleave();
});
this.addEventListener("dragstart", (event) => {
this.style.MozUserFocus = "";
}, true);
this.addEventListener("dragstart", (event) => {
if (this.mOverCloseButton) {
event.stopPropagation();
}
});
this.addEventListener("mousedown", (event) => {
let tabContainer = this.parentNode;
if (tabContainer._closeTabByDblclick &&
event.button == 0 &&
event.detail == 1) {
this._selectedOnFirstMouseDown = this.selected;
}
if (this.selected) {
this.style.MozUserFocus = "ignore";
} else if (event.originalTarget.classList.contains("tab-close-button") ||
event.originalTarget.classList.contains("tab-icon-sound") ||
event.originalTarget.classList.contains("tab-icon-overlay")) {
// Prevent tabbox.xml from selecting the tab.
event.stopPropagation();
}
if (event.button == 1) {
gBrowser.warmupTab(gBrowser._findTabToBlurTo(this));
}
if (event.button == 0 && tabContainer._multiselectEnabled) {
let shiftKey = event.shiftKey;
let accelKey = event.getModifierState("Accel");
if (shiftKey) {
const lastSelectedTab = gBrowser.lastMultiSelectedTab;
if (!accelKey) {
gBrowser.selectedTab = lastSelectedTab;
// Make sure selection is cleared when tab-switch doesn't happen.
gBrowser.clearMultiSelectedTabs(false);
}
gBrowser.addRangeToMultiSelectedTabs(lastSelectedTab, this);
// Prevent tabbox.xml from selecting the tab.
event.stopPropagation();
} else if (accelKey) {
// Ctrl (Cmd for mac) key is pressed
if (this.multiselected) {
gBrowser.removeFromMultiSelectedTabs(this, true);
} else if (this != gBrowser.selectedTab) {
gBrowser.addToMultiSelectedTabs(this, false);
gBrowser.lastMultiSelectedTab = this;
}
// Prevent tabbox.xml from selecting the tab.
event.stopPropagation();
} else if (!this.selected && this.multiselected) {
gBrowser.lockClearMultiSelectionOnce();
}
}
}, true);
this.addEventListener("mouseup", (event) => {
// Make sure that clear-selection is released.
// Otherwise selection using Shift key may be broken.
gBrowser.unlockClearMultiSelection();
this.style.MozUserFocus = "";
});
this.addEventListener("click", (event) => {
if (event.button != 0) {
return;
}
if (event.getModifierState("Accel") || event.shiftKey) {
return;
}
if (gBrowser.multiSelectedTabsCount > 0 &&
!event.originalTarget.classList.contains("tab-close-button") &&
!event.originalTarget.classList.contains("tab-icon-sound") &&
!event.originalTarget.classList.contains("tab-icon-overlay")) {
// Tabs were previously multi-selected and user clicks on a tab
// without holding Ctrl/Cmd Key
// Force positional attributes to update when the
// target (of the click) is the "active" tab.
let updatePositionalAttr = gBrowser.selectedTab == this;
gBrowser.clearMultiSelectedTabs(updatePositionalAttr);
}
if (event.originalTarget.classList.contains("tab-icon-sound") ||
(event.originalTarget.classList.contains("tab-icon-overlay") &&
(event.originalTarget.hasAttribute("soundplaying") ||
event.originalTarget.hasAttribute("muted") ||
event.originalTarget.hasAttribute("activemedia-blocked")))) {
if (this.multiselected) {
gBrowser.toggleMuteAudioOnMultiSelectedTabs(this);
} else {
this.toggleMuteAudio();
}
return;
}
if (event.originalTarget.classList.contains("tab-close-button")) {
if (this.multiselected) {
gBrowser.removeMultiSelectedTabs();
} else {
gBrowser.removeTab(this, {
animate: true,
byMouse: event.mozInputSource == MouseEvent.MOZ_SOURCE_MOUSE,
});
}
// This enables double-click protection for the tab container
// (see tabbrowser-tabs 'click' handler).
gBrowser.tabContainer._blockDblClick = true;
}
});
this.addEventListener("dblclick", (event) => {
if (event.button != 0) {
return;
}
// for the one-close-button case
if (event.originalTarget.classList.contains("tab-close-button")) {
event.stopPropagation();
}
let tabContainer = this.parentNode;
if (tabContainer._closeTabByDblclick &&
this._selectedOnFirstMouseDown &&
this.selected &&
!(event.originalTarget.classList.contains("tab-icon-sound") ||
event.originalTarget.classList.contains("tab-icon-overlay"))) {
gBrowser.removeTab(this, {
animate: true,
byMouse: event.mozInputSource == MouseEvent.MOZ_SOURCE_MOUSE,
});
}
}, true);
this.addEventListener("animationend", (event) => {
if (event.originalTarget.classList.contains("tab-loading-burst")) {
this.removeAttribute("bursting");
}
});
this.addEventListener("mouseover", this);
this.addEventListener("mouseout", this);
this.addEventListener("dragstart", this, true);
this.addEventListener("dragstart", this);
this.addEventListener("mousedown", this, true);
this.addEventListener("mouseup", this);
this.addEventListener("click", this);
this.addEventListener("dblclick", this, true);
this.addEventListener("animationend", this);
this._selectedOnFirstMouseDown = false;
@ -404,6 +248,175 @@ class MozTabbrowserTab extends MozElements.MozTab {
this._lastAccessed = this.selected ? Infinity : (aDate || Date.now());
}
on_mouseover(event) {
if (event.target.classList.contains("tab-close-button")) {
this.mOverCloseButton = true;
}
this._mouseenter();
}
on_mouseout(event) {
if (event.target.classList.contains("tab-close-button")) {
this.mOverCloseButton = false;
}
this._mouseleave();
}
on_dragstart(event) {
if (event.eventPhase == Event.CAPTURING_PHASE) {
this.style.MozUserFocus = "";
} else if (this.mOverCloseButton) {
event.stopPropagation();
}
}
on_mousedown(event) {
if (event.eventPhase == Event.BUBBLING_PHASE) {
super.on_mousedown(event);
return;
}
let tabContainer = this.parentNode;
if (tabContainer._closeTabByDblclick &&
event.button == 0 &&
event.detail == 1) {
this._selectedOnFirstMouseDown = this.selected;
}
if (this.selected) {
this.style.MozUserFocus = "ignore";
} else if (event.target.classList.contains("tab-close-button") ||
event.target.classList.contains("tab-icon-sound") ||
event.target.classList.contains("tab-icon-overlay")) {
// Prevent tabbox.js from selecting the tab.
event.stopPropagation();
}
if (event.button == 1) {
gBrowser.warmupTab(gBrowser._findTabToBlurTo(this));
}
if (event.button == 0 && tabContainer._multiselectEnabled) {
let shiftKey = event.shiftKey;
let accelKey = event.getModifierState("Accel");
if (shiftKey) {
const lastSelectedTab = gBrowser.lastMultiSelectedTab;
if (!accelKey) {
gBrowser.selectedTab = lastSelectedTab;
// Make sure selection is cleared when tab-switch doesn't happen.
gBrowser.clearMultiSelectedTabs(false);
}
gBrowser.addRangeToMultiSelectedTabs(lastSelectedTab, this);
// Prevent tabbox.xml from selecting the tab.
event.stopPropagation();
} else if (accelKey) {
// Ctrl (Cmd for mac) key is pressed
if (this.multiselected) {
gBrowser.removeFromMultiSelectedTabs(this, true);
} else if (this != gBrowser.selectedTab) {
gBrowser.addToMultiSelectedTabs(this, false);
gBrowser.lastMultiSelectedTab = this;
}
// Prevent tabbox.xml from selecting the tab.
event.stopPropagation();
} else if (!this.selected && this.multiselected) {
gBrowser.lockClearMultiSelectionOnce();
}
}
}
on_mouseup(event) {
// Make sure that clear-selection is released.
// Otherwise selection using Shift key may be broken.
gBrowser.unlockClearMultiSelection();
this.style.MozUserFocus = "";
}
on_click(event) {
if (event.button != 0) {
return;
}
if (event.getModifierState("Accel") || event.shiftKey) {
return;
}
if (gBrowser.multiSelectedTabsCount > 0 &&
!event.target.classList.contains("tab-close-button") &&
!event.target.classList.contains("tab-icon-sound") &&
!event.target.classList.contains("tab-icon-overlay")) {
// Tabs were previously multi-selected and user clicks on a tab
// without holding Ctrl/Cmd Key
// Force positional attributes to update when the
// target (of the click) is the "active" tab.
let updatePositionalAttr = gBrowser.selectedTab == this;
gBrowser.clearMultiSelectedTabs(updatePositionalAttr);
}
if (event.target.classList.contains("tab-icon-sound") ||
(event.target.classList.contains("tab-icon-overlay") &&
(event.target.hasAttribute("soundplaying") ||
event.target.hasAttribute("muted") ||
event.target.hasAttribute("activemedia-blocked")))) {
if (this.multiselected) {
gBrowser.toggleMuteAudioOnMultiSelectedTabs(this);
} else {
this.toggleMuteAudio();
}
return;
}
if (event.target.classList.contains("tab-close-button")) {
if (this.multiselected) {
gBrowser.removeMultiSelectedTabs();
} else {
gBrowser.removeTab(this, {
animate: true,
byMouse: event.mozInputSource == MouseEvent.MOZ_SOURCE_MOUSE,
});
}
// This enables double-click protection for the tab container
// (see tabbrowser-tabs 'click' handler).
gBrowser.tabContainer._blockDblClick = true;
}
}
on_dblclick(event) {
if (event.button != 0) {
return;
}
// for the one-close-button case
if (event.target.classList.contains("tab-close-button")) {
event.stopPropagation();
}
let tabContainer = this.parentNode;
if (tabContainer._closeTabByDblclick &&
this._selectedOnFirstMouseDown &&
this.selected &&
!(event.target.classList.contains("tab-icon-sound") ||
event.target.classList.contains("tab-icon-overlay"))) {
gBrowser.removeTab(this, {
animate: true,
byMouse: event.mozInputSource == MouseEvent.MOZ_SOURCE_MOUSE,
});
}
}
on_animationend(event) {
if (event.target.classList.contains("tab-loading-burst")) {
this.removeAttribute("bursting");
}
}
/**
* While it would make sense to track this in a field, the field will get nuked
* once the node is gone from the DOM, which causes us to think the tab is not
@ -419,8 +432,9 @@ class MozTabbrowserTab extends MozElements.MozTab {
let visibleTabs = tabContainer._getVisibleTabs();
let tabIndex = visibleTabs.indexOf(this);
if (this.selected)
if (this.selected) {
tabContainer._handleTabSelect();
}
if (tabIndex == 0) {
tabContainer._beforeHoveredTab = null;

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

@ -625,6 +625,10 @@
<vbox id="PanelUI-developerItems" class="panel-subview-body"/>
</panelview>
<panelview id="PanelUI-profiler" flex="1">
<iframe id="PanelUI-profilerIframe" className="PanelUI-developer-iframe" />
</panelview>
<panelview id="PanelUI-characterEncodingView" flex="1">
<vbox class="panel-subview-body">
<vbox id="PanelUI-characterEncodingView-pinned"

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

@ -1059,6 +1059,7 @@ var Policies = {
"SearchSuggestEnabled": {
onBeforeAddons(manager, param) {
setAndLockPref("browser.urlbar.suggest.searches", param);
setAndLockPref("browser.search.suggest.enabled", param);
},
},

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

@ -425,6 +425,7 @@ const POLICIES_TESTS = [
},
lockedPrefs: {
"browser.urlbar.suggest.searches": false,
"browser.search.suggest.enabled": false,
},
},

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

@ -92,9 +92,13 @@ EXTRA_JS_MODULES += [
BROWSER_CHROME_MANIFESTS += [
'safebrowsing/content/test/browser.ini',
'tests/browser/browser.ini',
'tests/browser/whats_new_page/browser.ini'
]
if CONFIG['MOZ_UPDATER']:
BROWSER_CHROME_MANIFESTS += [
'tests/browser/whats_new_page/browser.ini',
]
XPCSHELL_TESTS_MANIFESTS += [
'tests/unit/xpcshell.ini'
]

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

@ -78,9 +78,9 @@ class OrderedListBox {
setButtonState() {
let {upButton, downButton, removeButton} = this;
let {selectedIndex, itemCount} = this.richlistbox;
upButton.disabled = selectedIndex == 0;
upButton.disabled = selectedIndex <= 0;
downButton.disabled = selectedIndex == itemCount - 1;
removeButton.disabled = itemCount == 1 || !this.selectedItem.canRemove;
removeButton.disabled = itemCount <= 1 || !this.selectedItem.canRemove;
}
moveUp() {

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

@ -29,6 +29,9 @@ developer-button.label = Developer
# LOCALIZATION NOTE(developer-button.tooltiptext): %S is the keyboard shortcut
developer-button.tooltiptext2 = Open Web developer tools (%S)
profiler-button.label = Profiler
profiler-button.tooltiptext = Record a performance profile
sidebar-button.label = Sidebars
sidebar-button.tooltiptext2 = Show sidebars

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

@ -16,13 +16,13 @@
background: url("chrome://browser/skin/downloads/download-icons.svg#default-bar") center no-repeat;
}
#downloads-button[attention="success"] > #downloads-indicator-anchor > #downloads-indicator-icon,
#downloads-button[attention="success"] > #downloads-indicator-anchor > #downloads-indicator-progress-outer {
#downloads-button[attention="success"] > .toolbarbutton-badge-stack > #downloads-indicator-anchor > #downloads-indicator-icon,
#downloads-button[attention="success"] > .toolbarbutton-badge-stack > #downloads-indicator-anchor > #downloads-indicator-progress-outer {
-moz-context-properties: fill, fill-opacity;
fill: var(--toolbarbutton-icon-fill-attention);
fill-opacity: 1;
}
#downloads-button[progress] > #downloads-indicator-anchor > #downloads-indicator-progress-outer {
#downloads-button[progress] > .toolbarbutton-badge-stack > #downloads-indicator-anchor > #downloads-indicator-progress-outer {
background: url("chrome://browser/skin/downloads/download-icons.svg#progress-bar-bg") center no-repeat;
}
@ -109,7 +109,7 @@
/*** Download notifications ***/
#downloads-button[notification="start"] > #downloads-indicator-anchor > #downloads-indicator-icon {
#downloads-button[notification="start"] > .toolbarbutton-badge-stack > #downloads-indicator-anchor > #downloads-indicator-icon {
animation-name: downloadsIndicatorStartDip;
/* Upon changing the duration_delay below, please keep the delay time of
setTimeout() identical in indicator.js for this animation.
@ -145,7 +145,7 @@
to { transform: scale(1); animation-timing-function: ease-in; }
}
#downloads-button[notification="finish"] > #downloads-indicator-anchor > #downloads-indicator-icon {
#downloads-button[notification="finish"] > .toolbarbutton-badge-stack > #downloads-indicator-anchor > #downloads-indicator-icon {
animation-name: downloadsIndicatorFinishPulse;
animation-delay: 250ms;
animation-duration: 300ms;

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

@ -250,6 +250,14 @@ toolbar[brighttext] {
list-style-image: url("chrome://browser/skin/developer.svg");
}
#profiler-button {
list-style-image: url("chrome://devtools/skin/images/profiler-stopwatch.svg");
}
#PanelUI-profilerIframe {
width: 352px;
}
#preferences-button {
list-style-image: url("chrome://browser/skin/settings.svg");
}

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

@ -1469,6 +1469,9 @@ imply_option('MOZ_PGO',
set_config('MOZ_PROFILE_GENERATE',
depends_if('--enable-profile-generate')(lambda _: True))
set_define('MOZ_PROFILE_GENERATE',
depends_if('--enable-profile-generate')(lambda _: True))
js_option('--enable-profile-use',
help='Use a generated profile during the build')

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

@ -63,13 +63,18 @@ if __name__ == '__main__':
for path in prefpaths:
prefs.update(Preferences.read_prefs(path))
interpolation = {"server": "%s:%d" % httpd.httpd.server_address,
"OOP": "false"}
interpolation = {"server": "%s:%d" % httpd.httpd.server_address}
for k, v in prefs.items():
if isinstance(v, string_types):
v = v.format(**interpolation)
prefs[k] = Preferences.cast(v)
# Enforce e10s. This isn't in one of the user.js files because those
# are shared with android, which doesn't want this on. We can't
# interpolate because the formatting code only works for strings,
# and this is a bool pref.
prefs["browser.tabs.remote.autostart"] = True
profile = FirefoxProfile(profile=profilePath,
preferences=prefs,
addons=[os.path.join(
@ -80,10 +85,12 @@ if __name__ == '__main__':
env = os.environ.copy()
env["MOZ_CRASHREPORTER_NO_REPORT"] = "1"
env["XPCOM_DEBUG_BREAK"] = "warn"
# TODO should use e10s and gather data from all processes (bug 1196094).
# Note that unittest-required/user.js sets the autostart pref, but it
# is ignored by the code in nsAppRunner.
env["MOZ_FORCE_DISABLE_E10S"] = "1"
# We disable sandboxing to make writing profiling data actually work
# Bug 1553850 considers fixing this.
env["MOZ_DISABLE_CONTENT_SANDBOX"] = "1"
# Ensure different pids write to different files
env["LLVM_PROFILE_FILE"] = "default_%p_random_%m.profraw"
# For VC12+, make sure we can find the right bitness of pgort1x0.dll
if not substs.get('HAVE_64BIT_BUILD'):

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

@ -9,6 +9,7 @@ import {
getPaneCollapse,
getQuickOpenEnabled,
getSource,
startsWithThreadActor,
getFileSearchQuery,
getProjectDirectoryRoot,
} from "../selectors";
@ -181,6 +182,12 @@ export function clearProjectDirectoryRoot(cx: Context) {
export function setProjectDirectoryRoot(cx: Context, newRoot: string) {
return ({ dispatch, getState }: ThunkArgs) => {
// Remove the thread actor ID from the root path
const threadActor = startsWithThreadActor(getState(), newRoot);
if (threadActor) {
newRoot = newRoot.slice(threadActor.length + 1);
}
const curRoot = getProjectDirectoryRoot(getState());
if (newRoot && curRoot) {
const newRootArr = newRoot.replace(/\/+/g, "/").split("/");

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

@ -35,6 +35,7 @@ import {
createTree,
getDirectories,
isDirectory,
findSourceTreeNodes,
getSourceFromNode,
nodeHasChildren,
updateTree,
@ -80,8 +81,8 @@ type State = {
type SetExpanded = (item: TreeNode, expanded: boolean, altKey: boolean) => void;
function shouldAutoExpand(depth, item, debuggeeUrl) {
if (depth !== 1) {
function shouldAutoExpand(depth, item, debuggeeUrl, projectRoot) {
if (projectRoot != "" || depth !== 1) {
return false;
}
@ -214,20 +215,14 @@ class SourcesTree extends Component<Props, State> {
);
}
getRoots = () => {
const { projectRoot } = this.props;
const { sourceTree } = this.state;
getRoots = (sourceTree, projectRoot) => {
const sourceContents = sourceTree.contents[0];
const rootLabel = projectRoot.split("/").pop();
// The "sourceTree.contents[0]" check ensures that there are contents
// A custom root with no existing sources will be ignored
if (projectRoot && sourceContents) {
if (sourceContents && sourceContents.name !== rootLabel) {
return sourceContents.contents[0].contents;
}
return sourceContents.contents;
const roots = findSourceTreeNodes(sourceTree, projectRoot);
// NOTE if there is one root, we want to show its content
// TODO with multiple roots we should try and show the thread name
return roots && roots.length == 1 ? roots[0].contents : roots;
}
return sourceTree.contents;
@ -253,7 +248,7 @@ class SourcesTree extends Component<Props, State> {
threads={threads}
depth={depth}
focused={focused}
autoExpand={shouldAutoExpand(depth, item, debuggeeUrl)}
autoExpand={shouldAutoExpand(depth, item, debuggeeUrl, projectRoot)}
expanded={expanded}
focusItem={this.onFocus}
selectItem={this.selectItem}
@ -266,9 +261,9 @@ class SourcesTree extends Component<Props, State> {
};
renderTree() {
const { expanded, focused } = this.props;
const { expanded, focused, projectRoot } = this.props;
const { highlightItems, listItems, parentMap } = this.state;
const { highlightItems, listItems, parentMap, sourceTree } = this.state;
const treeProps = {
autoExpandAll: false,
@ -278,7 +273,7 @@ class SourcesTree extends Component<Props, State> {
getChildren: this.getChildren,
getParent: (item: $Shape<TreeNode>) => parentMap.get(item),
getPath: this.getPath,
getRoots: this.getRoots,
getRoots: () => this.getRoots(sourceTree, projectRoot),
highlightItems,
itemHeight: 21,
key: this.isEmpty() ? "empty" : "full",

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

@ -218,7 +218,7 @@ class SourceTreeItem extends Component<Props, State> {
if (isDirectory(item)) {
// Domain level
if (depth === 1) {
if (depth === 1 && projectRoot === "") {
return <AccessibleImage className="globe-small" />;
}
return <AccessibleImage className="folder" />;

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

@ -14,7 +14,7 @@ import { createSelector } from "reselect";
import { getDisplayName } from "../utils/workers";
import type { Selector } from "./types";
import type { Selector, State } from "./types";
import type { MainThread, WorkerList, Thread } from "../types";
import type { Action } from "../actions/types";
@ -95,4 +95,13 @@ export const getThreads: Selector<Thread[]> = createSelector(
(mainThread, workers) => [mainThread, ...sortBy(workers, getDisplayName)]
);
// checks if a path begins with a thread actor
// e.g "server1.conn0.child1/workerTarget22/context1/dbg-workers.glitch.me"
export function startsWithThreadActor(state: State, path: string) {
const threadActors = getThreads(state).map(t => t.actor);
const match = path.match(new RegExp(`(${threadActors.join("|")})\/(.*)`));
return match && match[1];
}
type OuterState = { debuggee: DebuggeeState };

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

@ -5,10 +5,12 @@
// @flow
import { createParentMap } from "./utils";
import flattenDeep from "lodash/flattenDeep";
import type { TreeNode, TreeDirectory } from "./types";
import type { Source } from "../../types";
function _traverse(subtree: TreeNode, source: Source) {
function findSourceItem(sourceTree: TreeDirectory, source: Source): ?TreeNode {
function _traverse(subtree: TreeNode) {
if (subtree.type === "source") {
if (subtree.contents.id === source.id) {
return subtree;
@ -17,12 +19,28 @@ function _traverse(subtree: TreeNode, source: Source) {
return null;
}
const matches = subtree.contents.map(child => _traverse(child, source));
const matches = subtree.contents.map(child => _traverse(child));
return matches && matches.filter(Boolean)[0];
}
return _traverse(sourceTree);
}
function findSourceItem(sourceTree: TreeDirectory, source: Source): ?TreeNode {
return _traverse(sourceTree, source);
export function findSourceTreeNodes(sourceTree: TreeDirectory, path: string) {
function _traverse(subtree: TreeNode) {
if (subtree.path.endsWith(path)) {
return subtree;
}
if (subtree.type === "directory") {
const matches = subtree.contents.map(child => _traverse(child));
return matches && matches.filter(Boolean);
}
}
const result = _traverse(sourceTree);
// $FlowIgnore
return Array.isArray(result) ? flattenDeep(result) : result;
}
function getAncestors(sourceTree: TreeDirectory, item: ?TreeNode) {

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

@ -12,7 +12,7 @@
export { addToTree } from "./addToTree";
export { collapseTree } from "./collapseTree";
export { formatTree } from "./formatTree";
export { getDirectories } from "./getDirectories";
export { getDirectories, findSourceTreeNodes } from "./getDirectories";
export { getFilenameFromPath, getURL } from "./getURL";
export { sortTree } from "./sortTree";
export { createTree, updateTree } from "./updateTree";

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

@ -6,7 +6,7 @@
import { makeMockSource } from "../../../utils/test-mockup";
import { getDirectories, createTree } from "../index";
import { getDirectories, findSourceTreeNodes, createTree } from "../index";
function formatDirectories(source, tree) {
const paths: any = getDirectories(source, tree);
@ -64,3 +64,33 @@ describe("getDirectories", () => {
]);
});
});
describe("findSourceTreeNodes", () => {
it("finds a node", () => {
const sources = createSources([
"http://src/main.js",
"http://src/utils/help.js",
"http://src/utils/print.js",
"http://workers/worker.js",
]);
const threads = [
{
actor: "FakeThread",
url: "http://a",
type: 1,
name: "FakeThread",
},
];
const debuggeeUrl = "http://a/";
const { sourceTree } = createTree({
sources,
debuggeeUrl,
threads,
});
const nodes = findSourceTreeNodes(sourceTree, "src") || [];
expect(nodes[0].path).toEqual("FakeThread/src");
});
});

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

@ -25,6 +25,7 @@ loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/debugge
loader.lazyRequireGetter(this, "BrowserMenus", "devtools/client/framework/browser-menus");
loader.lazyRequireGetter(this, "appendStyleSheet", "devtools/client/shared/stylesheet-utils", true);
loader.lazyRequireGetter(this, "ResponsiveUIManager", "devtools/client/responsive.html/manager", true);
loader.lazyRequireGetter(this, "AppConstants", "resource://gre/modules/AppConstants.jsm", true);
loader.lazyImporter(this, "BrowserToolboxProcess", "resource://devtools/client/framework/ToolboxProcess.jsm");
loader.lazyImporter(this, "ScratchpadManager", "resource://devtools/client/scratchpad/scratchpad-manager.jsm");
@ -113,6 +114,25 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = {
} catch (e) {
// devtools.recordreplay.enabled only exists on certain platforms.
}
// The profiler's popup is experimental. The plan is to eventually turn it on
// everywhere, but while it's under active development we don't want everyone
// having it enabled. For now the default pref is to turn it on with Nightly,
// with the option to flip the pref in other releases. This feature flag will
// go away once it is fully shipped.
const isPopupFeatureFlagEnabled = Services.prefs.getBoolPref(
"devtools.performance.popup.feature-flag", AppConstants.NIGHTLY_BUILD);
// If the feature flag is disabled, hide the menu item.
toggleMenuItem("menu_toggleProfilerButtonMenu", isPopupFeatureFlagEnabled);
if (isPopupFeatureFlagEnabled) {
// Did the user enable the profiler button in the menu? If it is then update the
// initial UI to show the menu item as checked.
if (Services.prefs.getBoolPref("devtools.performance.popup.enabled", false)) {
const cmd = doc.getElementById("menu_toggleProfilerButtonMenu");
cmd.setAttribute("checked", "true");
}
}
},
/**

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

@ -29,6 +29,10 @@ devtools.jar:
content/performance/index.xul (performance/index.xul)
content/performance-new/index.xhtml (performance-new/index.xhtml)
content/performance-new/frame-script.js (performance-new/frame-script.js)
content/performance-new/popup/icons/capture-profile-icon.svg (performance-new/popup/icons/capture-profile-icon.svg)
content/performance-new/popup/initializer.js (performance-new/popup/initializer.js)
content/performance-new/popup/popup.css (performance-new/popup/popup.css)
content/performance-new/popup/popup.html (performance-new/popup/popup.html)
content/memory/index.xhtml (memory/index.xhtml)
content/framework/toolbox-window.xul (framework/toolbox-window.xul)
content/framework/toolbox-options.xhtml (framework/toolbox-options.xhtml)

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

@ -44,6 +44,11 @@ browserToolboxMenu.accesskey = e
browserContentToolboxMenu.label = Browser Content Toolbox
browserContentToolboxMenu.accesskey = x
# LOCALIZATION NOTE (toggleProfilerButtonMenu.label): This is the label for the
# application menu item that toggles the profiler button to record performance profiles.
toggleProfilerButtonMenu.label = Enable Profiler Toolbar Icon
toggleProfilerButtonMenu.accesskey = P
webide.label = WebIDE
webide.accesskey = W

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

@ -38,6 +38,7 @@ loader.lazyRequireGetter(this, "openDocLink", "devtools/client/shared/link", tru
loader.lazyImporter(this, "BrowserToolboxProcess", "resource://devtools/client/framework/ToolboxProcess.jsm");
loader.lazyImporter(this, "ScratchpadManager", "resource://devtools/client/scratchpad/scratchpad-manager.jsm");
loader.lazyImporter(this, "ProfilerMenuButton", "resource://devtools/client/performance-new/popup/menu-button.jsm");
const isAboutDebuggingEnabled =
Services.prefs.getBoolPref("devtools.aboutdebugging.new-enabled", false);
@ -100,6 +101,13 @@ exports.menuitems = [
},
keyId: "browserConsole",
},
{ id: "menu_toggleProfilerButtonMenu",
l10nKey: "toggleProfilerButtonMenu",
checkbox: true,
oncommand(event) {
ProfilerMenuButton.toggle(event.target.ownerDocument);
},
},
{ id: "menu_responsiveUI",
l10nKey: "responsiveDesignMode",
oncommand(event) {

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

@ -6,6 +6,7 @@
DIRS += [
'components',
'store',
'popup',
]
DevToolsModules(

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

@ -0,0 +1,3 @@
# Profiler Popup
This directory controls the creation of a popup widget that can be used to record performance profiles. It is slightly different than the rest of the DevTools code, as it can be loaded independently of the rest of DevTools. The instrumentation from DevTools adds significant overhead to profiles, so this recording popup (and its shortcuts) enable a low-overhead profiling experience. This button can be enabled via the Tools -> Web Developer menu.

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

@ -0,0 +1,263 @@
/* 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";
/**
* This file contains all of the background logic for controlling the state and
* configuration of the profiler. It is in a JSM so that the logic can be shared
* with both the popup client, and the keyboard shortcuts. The shortcuts don't need
* access to any UI, and need to be loaded independent of the popup.
*/
// The following are not lazily loaded as they are needed during initialization.f
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { AppConstants } = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
const { loader } = ChromeUtils.import("resource://devtools/shared/Loader.jsm");
// The following utilities are lazily loaded as they are not needed when controlling the
// global state of the profiler, and only are used during specific funcationality like
// symbolication or capturing a profile.
ChromeUtils.defineModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
ChromeUtils.defineModuleGetter(this, "ProfilerGetSymbols",
"resource://gre/modules/ProfilerGetSymbols.jsm");
loader.lazyRequireGetter(this, "receiveProfile",
"devtools/client/performance-new/browser", true);
// This pref contains the JSON serialization of the popup's profiler state with
// a string key based off of the debug name and breakpad id.
const PROFILER_STATE_PREF = "devtools.performance.popup";
const DEFAULT_WINDOW_LENGTH = 20; // 20sec
// This Map caches the symbols from the shared libraries.
const symbolCache = new Map();
const primeSymbolStore = libs => {
for (const {path, debugName, debugPath, breakpadId} of libs) {
symbolCache.set(`${debugName}/${breakpadId}`, {path, debugPath});
}
};
const state = intializeState();
function adjustState(newState) {
// Deep clone the object, since this can be called through popup.html,
// which can be unloaded thus leaving this object dead.
newState = JSON.parse(JSON.stringify(newState));
Object.assign(state, newState);
try {
Services.prefs.setStringPref(PROFILER_STATE_PREF,
JSON.stringify(state));
} catch (error) {
console.error("Unable to save the profiler state for the popup.");
throw error;
}
}
function getSymbols(debugName, breakpadId) {
if (symbolCache.size === 0) {
primeSymbolStore(Services.profiler.sharedLibraries);
}
const cachedLibInfo = symbolCache.get(`${debugName}/${breakpadId}`);
if (!cachedLibInfo) {
throw new Error(
`The library ${debugName} ${breakpadId} is not in the ` +
"Services.profiler.sharedLibraries list, so the local path for it is not known " +
"and symbols for it can not be obtained. This usually happens if a content " +
"process uses a library that's not used in the parent process - " +
"Services.profiler.sharedLibraries only knows about libraries in the " +
"parent process.");
}
const {path, debugPath} = cachedLibInfo;
if (!OS.Path.split(path).absolute) {
throw new Error(
"Services.profiler.sharedLibraries did not contain an absolute path for " +
`the library ${debugName} ${breakpadId}, so symbols for this library can not ` +
"be obtained.");
}
return ProfilerGetSymbols.getSymbolTable(path, debugPath, breakpadId);
}
async function captureProfile() {
if (!state.isRunning) {
// The profiler is not active, ignore this shortcut.
return;
}
// Pause profiler before we collect the profile, so that we don't capture
// more samples while the parent process waits for subprocess profiles.
Services.profiler.PauseSampling();
const profile = await Services.profiler.getProfileDataAsArrayBuffer().catch(
e => {
console.error(e);
return {};
}
);
receiveProfile(profile, getSymbols);
Services.profiler.ResumeSampling();
}
/**
* Not all features are supported on every version of Firefox. Get the list of checked
* features, add a few defaults, and filter for what is actually supported.
*/
function getEnabledFeatures(features, threads) {
const enabledFeatures = Object.keys(features).filter(f => features[f]);
if (threads.length > 0) {
enabledFeatures.push("threads");
}
const supportedFeatures = Services.profiler.GetFeatures([]);
return enabledFeatures.filter(feature => supportedFeatures.includes(feature));
}
function startProfiler() {
const threads = state.threads.split(",");
const features = getEnabledFeatures(state.features, threads);
const windowLength = state.windowLength !== state.infiniteWindowLength
? state.windowLength
: 0;
const { buffersize, interval } = state;
Services.profiler.StartProfiler(buffersize, interval, features, threads, windowLength);
}
async function stopProfiler() {
Services.profiler.StopProfiler();
}
function toggleProfiler() {
if (state.isRunning) {
stopProfiler();
} else {
startProfiler();
}
}
function restartProfiler() {
stopProfiler();
startProfiler();
}
// This running observer was adapted from the web extension.
const isRunningObserver = {
_observers: new Set(),
observe(subject, topic, data) {
switch (topic) {
case "profiler-started":
case "profiler-stopped":
// Make the observer calls asynchronous.
const isRunningPromise = Promise.resolve(topic === "profiler-started");
for (const observer of this._observers) {
isRunningPromise.then(observer);
}
break;
}
},
_startListening() {
Services.obs.addObserver(this, "profiler-started");
Services.obs.addObserver(this, "profiler-stopped");
},
_stopListening() {
Services.obs.removeObserver(this, "profiler-started");
Services.obs.removeObserver(this, "profiler-stopped");
},
addObserver(observer) {
if (this._observers.size === 0) {
this._startListening();
}
this._observers.add(observer);
// Notify the observers the current state asynchronously.
Promise.resolve(Services.profiler.IsActive()).then(observer);
},
removeObserver(observer) {
if (this._observers.delete(observer) && this._observers.size === 0) {
this._stopListening();
}
},
};
function getStoredStateOrNull() {
// Pull out the stored state from preferences, it is a raw string.
const storedStateString = Services.prefs.getStringPref(PROFILER_STATE_PREF, "");
if (storedStateString === "") {
return null;
}
try {
// Attempt to parse the results.
return JSON.parse(storedStateString);
} catch (error) {
console.error(`Could not parse the stored state for the profile in the ` +
`preferences ${PROFILER_STATE_PREF}`);
}
return null;
}
function intializeState() {
const storedState = getStoredStateOrNull();
if (storedState) {
return storedState;
}
const features = {
java: false,
js: true,
leaf: true,
mainthreadio: false,
memory: false,
privacy: false,
responsiveness: true,
screenshots: false,
seqstyle: false,
stackwalk: true,
tasktracer: false,
trackopts: false,
jstracer: false,
};
if (AppConstants.platform === "android") {
// Java profiling is only meaningful on android.
features.java = true;
}
return {
isRunning: false,
settingsOpen: false,
buffersize: 10000000, // 90MB
windowLength: DEFAULT_WINDOW_LENGTH,
interval: 1,
features,
threads: "GeckoMain,Compositor",
};
}
isRunningObserver.addObserver(isRunning => {
adjustState({ isRunning });
});
const platform = AppConstants.platform;
var EXPORTED_SYMBOLS = [
"adjustState",
"captureProfile",
"state",
"startProfiler",
"stopProfiler",
"restartProfiler",
"toggleProfiler",
"isRunningObserver",
"platform",
];

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

@ -0,0 +1,11 @@
<!-- 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/. -->
<!-- This file was taken from command-screenshot.svg from the Firefox devtools.
- The camera metaphor doesn't really work well, and the fact that we're
- re-using an icon for a completely different use isn't great either. If
- anybody has any ideas for a replacement, I'd love to hear them. -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="#0b0b0b">
<path d="M13.6 5H11V3.5C11 2.7 10 2 9.2 2H6.8C6 2 5 2.7 5 3.5V5H2.4C1.6 5 1 5.6 1 6.4v6.5c0 .8.6 1.1 1.4 1.1h11.2c.8 0 1.4-.3 1.4-1.1V6.4c0-.8-.6-1.4-1.4-1.4zm.4 8H2V6h4V3h4v3h3.9l.1 7z"/>
<path d="M8 6.8c-1.3 0-2.4 1.1-2.4 2.4s1.1 2.4 2.4 2.4 2.4-1.1 2.4-2.4c0-1.3-1.1-2.4-2.4-2.4zm0 3.5c-.7 0-1.2-.5-1.2-1.1S7.3 8.1 8 8.1s1.2.5 1.2 1.1-.5 1.1-1.2 1.1z"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 960 B

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

@ -0,0 +1,32 @@
/* 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";
/**
* Initialize the require function through a BrowserLoader. This loader ensures
* that the popup can use require and has access to the window object.
*/
const { BrowserLoader } =
ChromeUtils.import("resource://devtools/client/shared/browser-loader.js");
const { require } = BrowserLoader({
baseURI: "resource://devtools/client/performance-new/popup/",
window,
});
/**
* The background.jsm manages the profiler state, and can be loaded multiple time
* for various components. This pop-up needs a copy, and it is also used by the
* profiler shortcuts. In order to do this, the background code needs to live in a
* JSM module, that can be shared with the DevTools keyboard shortcut manager.
*/
/**
* Require the popup code, and initialize it.
*/
const { initializePopup } = require("./popup");
document.addEventListener("DOMContentLoaded", () => {
initializePopup();
});

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

@ -0,0 +1,150 @@
/* 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";
/**
* This file controls the enabling and disabling of the menu button for the profiler.
* Care should be taken to keep it minimal as it can be run with browser initialization.
*/
ChromeUtils.defineModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
ChromeUtils.defineModuleGetter(this, "CustomizableUI",
"resource:///modules/CustomizableUI.jsm");
ChromeUtils.defineModuleGetter(this, "CustomizableWidgets",
"resource:///modules/CustomizableWidgets.jsm");
// The profiler's menu button and its popup can be enabled/disabled by the user.
// This is the pref to control whether the user has turned it on or not.
// This pref is repeated across many files in order to avoid loading this file if
// it's not needed. Make sure and search the rest of the codebase for other uses.
const BUTTON_ENABLED_PREF = "devtools.performance.popup.enabled";
const WIDGET_ID = "profiler-button";
function isEnabled() {
return Services.prefs.getBoolPref(BUTTON_ENABLED_PREF, false);
}
function setMenuItemChecked(document, isChecked) {
const menuItem = document.querySelector("#menu_toggleProfilerButtonMenu");
if (!menuItem) {
return;
}
menuItem.setAttribute("checked", isChecked);
}
/**
* Toggle the menu button, and initialize the widget if needed.
*
* @param {Object} document - The browser's document.
*/
function toggle(document) {
const toggledValue = !isEnabled();
Services.prefs.setBoolPref(BUTTON_ENABLED_PREF, toggledValue);
if (toggledValue) {
initialize();
CustomizableUI.addWidgetToArea(WIDGET_ID, CustomizableUI.AREA_NAVBAR);
} else {
setMenuItemChecked(document, false);
CustomizableUI.destroyWidget(WIDGET_ID);
// The widgets are not being properly destroyed. This is a workaround
// until Bug 1552565 lands.
const element = document.getElementById("PanelUI-profiler");
delete element._addedEventListeners;
}
}
/**
* This is a utility function to get the iframe from an event.
* @param {Object} The event fired by the CustomizableUI interface, contains a target.
*/
function getIframeFromEvent(event) {
const panelview = event.target;
const document = panelview.ownerDocument;
// Create the iframe, and append it.
const iframe = document.getElementById("PanelUI-profilerIframe");
if (!iframe) {
throw new Error("Unable to select the PanelUI-profilerIframe.");
}
return iframe;
}
/**
* This function creates the widget definition for the CustomizableUI. It should
* only be run if the profiler button is enabled.
*/
function initialize() {
const widget = CustomizableUI.getWidget(WIDGET_ID);
if (widget && widget.provider == CustomizableUI.PROVIDER_API) {
// This widget has already been created.
return;
}
let observer;
const item = {
id: WIDGET_ID,
type: "view",
viewId: "PanelUI-profiler",
tooltiptext: "profiler-button.tooltiptext",
onViewShowing: (event) => {
const iframe = getIframeFromEvent(event);
iframe.src = "chrome://devtools/content/performance-new/popup/popup.html";
// Provide a mechanism for the iframe to close the popup.
iframe.contentWindow.gClosePopup = () => {
CustomizableUI.hidePanelForNode(iframe);
};
// Provide a mechanism for the iframe to resize the popup.
iframe.contentWindow.gResizePopup = height => {
iframe.style.height = `${Math.min(600, height)}px`;
};
},
onViewHiding(event) {
const iframe = getIframeFromEvent(event);
// Unset the iframe src so that when the popup DOM element is moved, the popup's
// contents aren't re-initialized.
iframe.src = "";
},
onBeforeCreated: (document) => {
setMenuItemChecked(document, true);
observer = {
observe(subject, topic, data) {
switch (topic) {
case "profiler-started": {
const button = document.querySelector("#profiler-button");
if (button) {
// Photon blue-60.
button.style.fill = "#0060df";
}
break;
}
case "profiler-stopped": {
const button = document.querySelector("#profiler-button");
if (button) {
button.style.fill = "";
}
break;
}
}
},
};
Services.obs.addObserver(observer, "profiler-started");
Services.obs.addObserver(observer, "profiler-stopped");
},
onDestroyed: () => {
Services.obs.removeObserver(observer, "profiler-started");
Services.obs.removeObserver(observer, "profiler-stopped");
},
};
CustomizableUI.createWidget(item);
CustomizableWidgets.push(item);
}
const ProfilerMenuButton = { toggle, initialize };
var EXPORTED_SYMBOLS = ["ProfilerMenuButton"];

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

@ -0,0 +1,13 @@
# vim: set filetype=python:
# 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/.
DevToolsModules(
'background.jsm',
'menu-button.jsm',
'popup.js',
)
with Files('**'):
BUG_COMPONENT = ('Core', 'Gecko Profiler')

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

@ -0,0 +1,406 @@
/* 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/. */
html {
background: rgb(250,250,250);
font: message-box;
-moz-user-select: none;
cursor: default;
overflow: auto;
}
* {
flex-shrink: 0;
}
body {
margin: 0;
/**
* We had to use `max-width` instead of `width` here because of a bug on Firefox
* that causes a horizontal scrollbar when there is a vertical scrollbar on Linux.
* This is not a problem on platforms that have a floating scrollbar that doesn't
* take additional space, but on platforms that we don't have floating scrollbar,
* it takes some space from the body element and causes horizontal scrollbar to appear.
* See: https://bugzilla.mozilla.org/show_bug.cgi?id=1400279
*/
max-width: 32em;
}
.status-display {
margin: 0;
padding: 10px 4px;
position: relative;
}
.status-display::before {
content: '';
display: inline-block;
width: 17px;
height: 17px;
vertical-align: top;
margin: -2px 3px -20px;
}
:root.status-stopped .status-display:not(.status-display-stopped) { display: none; }
:root.status-running .status-display:not(.status-display-running) { display: none; }
.status-display-stopped {
background: hsl(210, 80%, 85%);
}
.status-display-running {
background: hsl(90, 70%, 70%);
}
.status-display-stopped::before {
background: hsl(210, 70%, 60%);
}
.status-display-running::before {
background: hsl(90, 80%, 40%);
border-radius: 100%;
}
.status-display-button {
position: absolute;
top: 7px;
right: 7px;
padding: 2.5px;
border: 0.5px solid transparent;
border-radius: 2px;
}
.status-display-button:hover {
box-shadow: inset 0 0.5px hsla(0,0%,100%,0.3);
color: black;
}
.status-display-button:hover:active {
box-shadow: inset 0 2px 5px rgba(0,0,0,0.15);
}
.button-start {
border-color: hsl(210, 30%, 60%);
background: rgba(0,0,0,0.08);
color: hsl(210, 80%, 20%);
}
.button-cancel {
border-color: hsl(90, 40%, 50%);
background: rgba(0,0,0,0.08);
color: hsl(90, 80%, 20%);
}
.button-start:hover {
border-color: hsl(90, 40%, 50%);
background: linear-gradient(hsl(90, 70%, 68%), hsl(90, 70%, 58%));
color: hsl(90, 80%, 20%);
}
.button-cancel:hover {
background: linear-gradient(hsl(0, 95%, 68%), hsl(0, 95%, 58%));
border-color: hsl(0, 90%, 30%);
}
.button-start:hover:active {
background: linear-gradient(hsl(90, 70%, 50%), hsl(90, 70%, 45%));
}
.button-cancel:hover:active {
background: linear-gradient(hsl(0, 90%, 50%), hsl(0, 90%, 45%));
}
#button-capture {
margin: 6px 5px 5px;
height: auto;
text-align: left;
padding: 5px 2px;
padding-left: 32px;
border: 1px solid #DDD;
box-shadow: 0 1px rgba(0,0,0,0.3);
border-radius: 5px;
background: linear-gradient(#FAFAFA, #EEE);
display: block;
position: relative;
}
:root.status-stopped #button-capture {
color: GrayText;
}
:root.status-running #button-capture:hover {
background: linear-gradient(#EEE, #DDD);
}
:root.status-running #button-capture:hover:active {
background: #CCC;
border-color: #BBB;
}
#capture-label {
display: flex;
flex-flow: row nowrap;
margin-bottom: 4px;
font-size: 14px;
}
#capture-label::before {
content: '';
position: absolute;
width: 16px;
height: 16px;
background: url(icons/capture-profile-icon.svg);
top: 6px;
left: 10px;
}
:root.status-stopped #capture-label::before {
opacity: 0.5;
}
.keyboard-hint {
font-size: 1rem;
font-weight: normal;
flex: 1;
text-align: center;
}
kbd {
font-size: 10px;
background-color: hsla(0,0%,100%,0.4);
border: 1px solid #CCC;
border-radius: 0.2em;
display: inline-block;
padding: 0.1em 0.35em;
box-shadow: 0 0.1em 0 #BBB;
margin: 0 0.15em;
font-family: inherit;
}
#help-capture {
margin: 0;
}
.info-density {
margin: 4px 12px;
display: grid;
grid-template-columns: 7em auto;
grid-template-rows: auto;
}
.info-density > dt {
grid-column: 1;
padding: 2px 0;
}
.info-density > dd {
grid-column: 2;
margin: 0;
padding: 5px 0 3px;
}
.settings {
background: #FFFFFF;
}
.settings:not(.open) > .settings-content,
.settings:not(.open) > .settings-apply-button-wrapper {
display: none;
}
#settings-label {
margin: 0;
padding: 4px 10px;
font-size: 14px;
font-weight: bold;
background: #EEE;
}
#settings-label:hover {
background: #DDD;
}
#settings-label:hover:active {
background: #CCC;
}
#settings-label::before {
content: '';
display: inline-block;
border-left: 9px solid #BBB;
border-top: 5px solid transparent;
border-bottom: 5px solid transparent;
margin-right: 5px;
}
.settings.open > #settings-label::before {
transform: rotate(90deg);
}
.discrete-level {
display: flex;
height: 100%;
flex-flow: row nowrap;
justify-content: space-between;
}
.discrete-level-notch {
flex: 1;
margin-right: 1px;
border: 1px solid rgba(0,0,0,0.2);
border-radius: 2px;
}
.discrete-level-notch.normal.active {
border-color: hsl(90, 90%, 40%);
background-color: hsla(90, 90%, 40%, 0.5);
}
.discrete-level-notch.warning.active {
border-color: hsl(45, 100%, 49%);
background-color: hsla(45, 100%, 49%, 0.5);
}
.discrete-level-notch.critical.active {
border-color: hsl(0, 90%, 40%);
background-color: hsla(0, 90%, 40%, 0.5);
}
.settings-content {
margin: 0;
padding: 0 10px 18px;
line-height: 22px;
display: grid;
grid-template-columns: 8em auto;
grid-template-rows: auto;
}
.settings-setting-label {
margin: 0;
font-size: 100%;
font-weight: normal;
}
.range-with-value {
display: flex;
flex-flow: row nowrap;
}
.range-input {
margin: 0;
width: 0;
flex: 1;
}
.range-value {
margin-left: 10px;
width: 4em;
white-space: nowrap;
flex-shrink: 0;
}
.settings-textbox {
min-width: 0;
}
.features-list {
margin: 0;
padding: 2px 0 0;
line-height: 20px;
}
.features-list > li {
display: block;
margin: 0;
padding: 0;
}
.settings-apply-button-wrapper {
padding: 4px 10px;
margin: 0;
text-align: right;
bottom: 0;
right: 0;
position: fixed;
width: 100%;
background: #eee;
}
.perf-settings-row {
display: flex;
overflow: hidden;
line-height: 1.8;
}
.perf-settings-row.focused {
background-color: #0074e8;
color: #ffffff;
}
.perf-settings-text-input {
width: 100%;
padding: 4px;
box-sizing: border-box;
}
.perf-settings-text-label {
flex: 1;
}
.perf-settings-details-contents {
padding: 4px;
margin: 0 0 18px;
border: #ededf0 1px solid;
background-color: #f9f9fa;
}
.perf-settings-details {
grid-column-start: 1;
grid-column-end: 3;
}
.perf-settings-summary {
height: 30px;
cursor: default;
-moz-user-select: none;
}
.perf-settings-thread-columns {
margin-bottom: 20px;
display: flex;
line-height: 2;
}
.perf-settings-thread-column {
flex: 1;
}
.perf-settings-checkbox-label {
display: block;
}
.perf-settings-feature-label {
margin: 8px 0;
display: flex;
flex-wrap: wrap;
}
.perf-settings-checkbox {
align-self: flex-start;
}
.perf-settings-feature-title {
margin-left: 20px;
flex: 1 100%;
line-height: 1.6;
}
.perf-settings-feature-name {
color: #0060df;
line-height: 1.6;
}
.perf-settings-subtext {
font-weight: bold;
}

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

@ -0,0 +1,181 @@
<!-- 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/. -->
<!DOCTYPE html>
<html class="status-running">
<head>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="popup.css">
</head>
<body>
<p class="status-display status-display-running">
The profiler is recording.
<input type="button" class="status-display-button button-cancel" value="Discard &amp; Stop">
</p>
<p class="status-display status-display-stopped">
The profiler is stopped.
<input type="button" class="status-display-button button-start" value="Start">
</p>
<button id="button-capture">
<strong id="capture-label">Capture Profile <span class="keyboard-hint"><kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>2</kbd></span></strong>
<p id="help-capture">Capture the current contents of the profile buffer and open the profile in a new tab.</p>
</button>
<dl class="info-density">
<dt>Overhead:</dt>
<dd>
<div class="discrete-level">
<span class="discrete-level-notch normal active"></span>
<span class="discrete-level-notch normal active"></span>
<span class="discrete-level-notch normal active"></span>
<span class="discrete-level-notch normal active"></span>
<span class="discrete-level-notch normal active"></span>
<span class="discrete-level-notch normal active"></span>
<span class="discrete-level-notch normal active"></span>
<span class="discrete-level-notch normal active"></span>
<span class="discrete-level-notch normal active"></span>
<span class="discrete-level-notch normal active"></span>
<span class="discrete-level-notch normal active"></span>
<span class="discrete-level-notch normal active"></span>
<span class="discrete-level-notch warning active"></span>
<span class="discrete-level-notch warning active"></span>
<span class="discrete-level-notch warning active"></span>
<span class="discrete-level-notch warning active"></span>
<span class="discrete-level-notch warning inactive"></span>
<span class="discrete-level-notch warning inactive"></span>
<span class="discrete-level-notch warning inactive"></span>
<span class="discrete-level-notch critical inactive"></span>
<span class="discrete-level-notch critical inactive"></span>
<span class="discrete-level-notch critical inactive"></span>
<span class="discrete-level-notch critical inactive"></span>
<span class="discrete-level-notch critical inactive"></span>
<span class="discrete-level-notch critical inactive"></span>
</div>
</dd>
</dl>
<section class="settings">
<h1 id="settings-label">Settings</h1>
<section class="settings-content">
<h1 class="settings-setting-label">Interval:</h1>
<span class="range-with-value">
<input type="range" class="range-input interval-range" min="0" max="100">
<span class="range-value interval-value">1 ms</span>
</span>
<h1 class="settings-setting-label windowlength">Window length:</h1>
<span class="range-with-value windowlength">
<input type="range" class="range-input windowlength-range" min="0" max="100">
<span class="range-value windowlength-value">20 sec</span>
</span>
<h1 class="settings-setting-label">Buffer size:</h1>
<span class="range-with-value">
<input type="range" class="range-input buffersize-range" min="0" max="100">
<span class="range-value buffersize-value">90 MB</span>
</span>
<div class="perf-settings-details">
<summary class="perf-settings-summary" id="perf-settings-threads-summary">Threads:</summary>
<div class="perf-settings-details-contents">
<div class="perf-settings-thread-columns">
<div class="perf-settings-thread-column"><label class="perf-settings-checkbox-label" title="The main processes for both the parent process, and content processes"><input
class="perf-settings-checkbox" id="perf-settings-thread-checkbox-gecko-main" type="checkbox" value="GeckoMain" />GeckoMain</label><label
class="perf-settings-checkbox-label" title="Composites together different painted elements on the page."><input
class="perf-settings-checkbox" id="perf-settings-thread-checkbox-compositor" type="checkbox" value="Compositor" />Compositor</label><label
class="perf-settings-checkbox-label" title="This handle both web workers and service workers"><input class="perf-settings-checkbox"
id="perf-settings-thread-checkbox-dom-worker" type="checkbox" value="DOM Worker" />DOM Worker</label><label
class="perf-settings-checkbox-label" title="When WebRender is enabled, the thread that executes OpenGL calls"><input
class="perf-settings-checkbox" id="perf-settings-thread-checkbox-renderer" type="checkbox" value="Renderer" />Renderer</label></div>
<div class="perf-settings-thread-column"><label class="perf-settings-checkbox-label" title="The WebRender RenderBackend thread"><input
class="perf-settings-checkbox" id="perf-settings-thread-checkbox-render-backend" type="checkbox" value="RenderBackend" />RenderBackend</label><label
class="perf-settings-checkbox-label" title="When off-main-thread painting is enabled, the thread on which painting happens"><input
class="perf-settings-checkbox" id="perf-settings-thread-checkbox-paint-worker" type="checkbox" value="PaintWorker" />PaintWorker</label><label
class="perf-settings-checkbox-label" title="Style computation is split into multiple threads"><input class="perf-settings-checkbox"
id="perf-settings-thread-checkbox-style-thread" type="checkbox" value="StyleThread" />StyleThread</label><label
class="perf-settings-checkbox-label" title="The thread where networking code runs any blocking socket calls"><input
class="perf-settings-checkbox" id="perf-settings-thread-checkbox-socket-thread" type="checkbox" value="Socket Thread" />Socket
Thread</label></div>
<div class="perf-settings-thread-column"><label class="perf-settings-checkbox-label" title="TODO"><input class="perf-settings-checkbox"
id="perf-settings-thread-checkbox-stream-trans" type="checkbox" value="StreamTrans" />StreamTrans</label><label
class="perf-settings-checkbox-label" title="Image decoding threads"><input class="perf-settings-checkbox"
id="perf-settings-thread-checkbox-img-decoder" type="checkbox" value="ImgDecoder" />ImgDecoder</label><label
class="perf-settings-checkbox-label" title="DNS resolution happens on this thread"><input class="perf-settings-checkbox"
id="perf-settings-thread-checkbox-dns-resolver" type="checkbox" value="DNS Resolver" />DNS Resolver</label></div>
</div>
<div class="perf-settings-row"><label class="perf-settings-text-label" title="These thread names are a comma separated list that is used to enable profiling of the threads in the profiler. The name needs to be only a partial match of the thread name to be included. It is whitespace sensitive.">
<div>Add custom threads by name:</div><input class="perf-settings-text-input" id="perf-settings-thread-text"
type="text" value="GeckoMain,Compositor" />
</label></div>
</div>
</div>
<div class="perf-settings-details">
<summary class="perf-settings-summary" id="perf-settings-features-summary">Features:</summary>
<div class="perf-settings-details-contents">
<label class="perf-settings-checkbox-label perf-settings-feature-label"><input
class="perf-settings-checkbox" id="perf-settings-feature-checkbox-stackwalk" type="checkbox" value="stackwalk" />
<div class="perf-settings-feature-name">Native Stacks</div>
<div class="perf-settings-feature-title">Record native stacks (C++ and Rust). This is not available on all
platforms.<span class="perf-settings-subtext"> (Recommended on by default.)</span></div>
</label><label class="perf-settings-checkbox-label perf-settings-feature-label"><input class="perf-settings-checkbox"
id="perf-settings-feature-checkbox-js" type="checkbox" value="js" />
<div class="perf-settings-feature-name">JavaScript</div>
<div class="perf-settings-feature-title">Record JavaScript stack information, and interleave it with native
stacks.<span class="perf-settings-subtext"> (Recommended on by default.)</span></div>
</label><label class="perf-settings-checkbox-label perf-settings-feature-label" id="java"><input class="perf-settings-checkbox"
id="perf-settings-feature-checkbox-java" type="checkbox" value="java" />
<div class="perf-settings-feature-name">Java</div>
<div class="perf-settings-feature-title">Profile Java code.</div>
</label><label class="perf-settings-checkbox-label perf-settings-feature-label"><input class="perf-settings-checkbox"
id="perf-settings-feature-checkbox-responsiveness" type="checkbox" value="responsiveness" />
<div class="perf-settings-feature-name">Responsiveness</div>
<div class="perf-settings-feature-title">Collect thread responsiveness information.<span class="perf-settings-subtext">
(Recommended on by default.)</span></div>
</label><label class="perf-settings-checkbox-label perf-settings-feature-label"><input class="perf-settings-checkbox"
id="perf-settings-feature-checkbox-leaf" type="checkbox" value="leaf" />
<div class="perf-settings-feature-name">Native Leaf Stack</div>
<div class="perf-settings-feature-title">Record the native memory address of the leaf-most stack. This could be
useful on platforms that do not support stack walking.<span class="perf-settings-subtext"> (Recommended on by
default.)</span></div>
</label><label class="perf-settings-checkbox-label perf-settings-feature-label"><input class="perf-settings-checkbox"
id="perf-settings-feature-checkbox-screenshots" type="checkbox" value="screenshots" />
<div class="perf-settings-feature-name">Screenshots</div>
<div class="perf-settings-feature-title">Capture screenshots of browser windows.</div>
</label><label class="perf-settings-checkbox-label perf-settings-feature-label"><input class="perf-settings-checkbox"
id="perf-settings-feature-checkbox-mainthreadio" type="checkbox" value="mainthreadio" />
<div class="perf-settings-feature-name">Main Thread IO</div>
<div class="perf-settings-feature-title">Record main thread I/O markers.</div>
</label><label class="perf-settings-checkbox-label perf-settings-feature-label"><input class="perf-settings-checkbox"
id="perf-settings-feature-checkbox-memory" type="checkbox" value="memory" />
<div class="perf-settings-feature-name">Memory</div>
<div class="perf-settings-feature-title">Add memory measurements to the samples, this includes resident set
size (RSS) and unique set size (USS).</div>
</label><label class="perf-settings-checkbox-label perf-settings-feature-label"><input class="perf-settings-checkbox"
id="perf-settings-feature-checkbox-privacy" type="checkbox" value="privacy" />
<div class="perf-settings-feature-name">Privacy</div>
<div class="perf-settings-feature-title">Remove some potentially user-identifiable information.</div>
</label><label class="perf-settings-checkbox-label perf-settings-feature-label"><input class="perf-settings-checkbox"
id="perf-settings-feature-checkbox-seqstyle" type="checkbox" value="seqstyle" />
<div class="perf-settings-feature-name">Sequential Styling</div>
<div class="perf-settings-feature-title">Disable parallel traversal in styling.</div>
</label><label class="perf-settings-checkbox-label perf-settings-feature-label"><input class="perf-settings-checkbox"
id="perf-settings-feature-checkbox-trackopts" type="checkbox" value="trackopts" />
<div class="perf-settings-feature-name">JIT Optimizations</div>
<div class="perf-settings-feature-title">Track JIT optimizations in the JS engine.</div>
</label><label class="perf-settings-checkbox-label perf-settings-feature-label"><input class="perf-settings-checkbox"
id="perf-settings-feature-checkbox-tasktracer" type="checkbox" value="tasktracer" />
<div class="perf-settings-feature-name">TaskTracer</div>
<div class="perf-settings-feature-title">Enable TaskTracer (Experimental, requires custom build.)</div>
</label><label class="perf-settings-checkbox-label perf-settings-feature-label"><input class="perf-settings-checkbox"
id="perf-settings-feature-checkbox-jstracer" type="checkbox" value="jstracer" />
<div class="perf-settings-feature-name">JSTracer</div>
<div class="perf-settings-feature-title">Trace JS engine (Experimental, requires custom build.)</div>
</label>
</div>
</div>
</section>
<section class="settings-apply-button-wrapper"><input type="button" class="settings-apply-button" value="Apply (Restart Profiler)"></section>
</section>
<script src="initializer.js"></script>
</body>
</html>

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

@ -0,0 +1,385 @@
/* 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 background =
ChromeUtils.import("resource://devtools/client/performance-new/popup/background.jsm");
const intervalScale = makeExponentialScale(0.01, 100);
const buffersizeScale = makeExponentialScale(10000, 100000000);
// Window Length accepts a numerical value between 1-N. We also need to put an
// infinite number at the end of the window length slider. Therefore, the max
// value pretends like it's infinite in the slider.
// The maximum value of window length is 300 seconds. For that reason, we are
// treating 400 as infinity.
const infiniteWindowLength = 400;
const windowLengthScale = makeExponentialScale(1, infiniteWindowLength);
const PROFILE_ENTRY_SIZE = 9; // sizeof(double) + sizeof(char), http://searchfox.org/mozilla-central/rev/e8835f52eff29772a57dca7bcc86a9a312a23729/tools/profiler/core/ProfileEntry.h#73
const featurePrefix = "perf-settings-feature-checkbox-";
const features = [
"java",
"js",
"leaf",
"mainthreadio",
"memory",
"privacy",
"responsiveness",
"screenshots",
"seqstyle",
"stackwalk",
"tasktracer",
"jstracer",
"trackopts",
];
const threadPrefix = "perf-settings-thread-checkbox-";
// A map of element ID suffixes to their corresponding profile thread name, for
// creating ID -> name mappings, e.g.`$threadPrefix}dom-worker` - DOM Worker.
const threadMap = {
compositor: "Compositor",
"dns-resolver": "DNS Resolver",
"dom-worker": "DOM Worker",
"gecko-main": "GeckoMain",
"img-decoder": "ImgDecoder",
"paint-worker": "PaintWorker",
"render-backend": "RenderBackend",
renderer: "Renderer",
"socket-thread": "Socket Thread",
"stream-trans": "StreamTrans",
"style-thread": "StyleThread",
};
function initializePopup() {
const updateIsRunning = () => {
renderState(background.state);
};
background.isRunningObserver.addObserver(updateIsRunning);
window.addEventListener("unload", () => {
background.isRunningObserver.removeObserver(updateIsRunning);
});
for (const name of features) {
setupFeatureCheckbox(name);
}
for (const name in threadMap) {
setupThreadCheckbox(name);
}
document
.querySelector("#perf-settings-thread-text")
.addEventListener("change", async e => {
background.adjustState({ threads: e.target.value });
renderState(background.state);
});
document
.querySelector(".settings-apply-button")
.addEventListener("click", async () => {
background.restartProfiler();
});
document.querySelector(".button-start").addEventListener("click", async () => {
background.startProfiler();
background.adjustState({ isRunning: true });
renderState(background.state);
});
document.querySelector(".button-cancel").addEventListener("click", async () => {
background.stopProfiler();
background.adjustState({ isRunning: false });
renderState(background.state);
});
document
.querySelector("#button-capture")
.addEventListener("click", async () => {
if (document.documentElement.classList.contains("status-running")) {
await background.captureProfile();
window.gClosePopup();
}
});
document
.querySelector("#settings-label")
.addEventListener("click", async () => {
const { settingsOpen } = background.state;
background.adjustState({
settingsOpen: !settingsOpen,
});
renderState(background.state);
});
document.querySelector(".interval-range").addEventListener("input", async e => {
const frac = e.target.value / 100;
background.adjustState({
interval: intervalScale.fromFractionToSingleDigitValue(frac),
});
renderState(background.state);
});
document
.querySelector(".buffersize-range")
.addEventListener("input", async e => {
const frac = e.target.value / 100;
background.adjustState({
buffersize: buffersizeScale.fromFractionToSingleDigitValue(frac),
});
renderState(background.state);
});
document
.querySelector(".windowlength-range")
.addEventListener("input", async e => {
const frac = e.target.value / 100;
background.adjustState({
windowLength: windowLengthScale.fromFractionToSingleDigitValue(frac),
});
renderState(background.state);
});
window.onload = () => {
// Letting the background script know how the infiniteWindowLength is represented.
background.adjustState({
infiniteWindowLength,
});
};
renderState(background.state);
}
function renderState(state) {
const { isRunning, settingsOpen, interval, buffersize, windowLength } = state;
document.documentElement.classList.toggle("status-running", isRunning);
document.documentElement.classList.toggle("status-stopped", !isRunning);
document.querySelector(".settings").classList.toggle("open", settingsOpen);
document.querySelector(".interval-value").textContent = `${interval} ms`;
document.querySelector(".buffersize-value").textContent = prettyBytes(
buffersize * PROFILE_ENTRY_SIZE
);
document.querySelector(".windowlength-value").textContent = windowLength ===
infiniteWindowLength
? ``
: `${windowLength} sec`;
const overhead = calculateOverhead(state);
const overheadDiscreteContainer = document.querySelector(".discrete-level");
for (let i = 0; i < overheadDiscreteContainer.children.length; i++) {
const discreteLevelNotch = overheadDiscreteContainer.children[i];
const isActive =
i <=
Math.round(overhead * (overheadDiscreteContainer.children.length - 1));
discreteLevelNotch.classList.toggle("active", isActive);
discreteLevelNotch.classList.toggle("inactive", !isActive);
}
renderControls(state);
window.requestAnimationFrame(() => {
if (window.gResizePopup) {
window.gResizePopup(document.body.clientHeight);
}
});
}
function renderControls(state) {
document.querySelector(".interval-range").value =
intervalScale.fromValueToFraction(state.interval) * 100;
document.querySelector(".buffersize-range").value =
buffersizeScale.fromValueToFraction(state.buffersize) * 100;
document.querySelector(".windowlength-range").value =
windowLengthScale.fromValueToFraction(state.windowLength) * 100;
for (const name of features) {
document.getElementById(featurePrefix + name).value = state[name];
}
for (const name in threadMap) {
document.getElementById(
threadPrefix + name
).checked = state.threads.includes(threadMap[name]);
}
document.querySelector("#perf-settings-thread-text").value = state.threads;
}
function clamp(val, min, max) {
return Math.max(min, Math.min(max, val));
}
function lerp(frac, rangeStart, rangeEnd) {
return (1 - frac) * rangeStart + frac * rangeEnd;
}
function scaleRangeWithClamping(
val,
sourceRangeStart,
sourceRangeEnd,
destRangeStart,
destRangeEnd
) {
const frac = clamp(
(val - sourceRangeStart) / (sourceRangeEnd - sourceRangeStart),
0,
1
);
return lerp(frac, destRangeStart, destRangeEnd);
}
function calculateOverhead(state) {
const overheadFromSampling =
scaleRangeWithClamping(
Math.log(state.interval),
Math.log(0.05),
Math.log(1),
1,
0
) +
scaleRangeWithClamping(
Math.log(state.interval),
Math.log(1),
Math.log(100),
0.1,
0
);
const overheadFromBuffersize = scaleRangeWithClamping(
Math.log(state.buffersize),
Math.log(10),
Math.log(1000000),
0,
0.1
);
const overheadFromStackwalk = state.stackwalk ? 0.05 : 0;
const overheadFromResponsiveness = state.responsiveness ? 0.05 : 0;
const overheadFromJavaScrpt = state.js ? 0.05 : 0;
const overheadFromSeqStyle = state.seqstyle ? 0.05 : 0;
const overheadFromTaskTracer = state.tasktracer ? 0.05 : 0;
const overheadFromJSTracer = state.jstracer ? 0.05 : 0;
return clamp(
overheadFromSampling +
overheadFromBuffersize +
overheadFromStackwalk +
overheadFromResponsiveness +
overheadFromJavaScrpt +
overheadFromSeqStyle +
overheadFromTaskTracer +
overheadFromJSTracer,
0,
1
);
}
/**
* This helper initializes and adds listeners to the features checkboxes that
* will adjust the profiler state when changed.
*/
async function setupFeatureCheckbox(name) {
// Java profiling is only meaningful on android.
if (name == "java") {
if (background.platform !== "android") {
document.querySelector("#java").style.display = "none";
return;
}
}
const checkbox = document.querySelector(`#${featurePrefix}${name}`);
checkbox.checked = background.state.features[name];
checkbox.addEventListener("change", async e => {
const newFeatures = Object.assign({}, background.state.features);
newFeatures[name] = e.target.checked;
background.adjustState({ features: newFeatures });
renderState(background.state);
});
}
/**
* This helper initializes and adds listeners to the threads checkboxes that
* will adjust the profiler state when changed.
*/
async function setupThreadCheckbox(name) {
const checkbox = document.querySelector(`#${threadPrefix}${name}`);
checkbox.checked = background.state.threads.includes(threadMap[name]);
checkbox.addEventListener("change", async e => {
let threads = background.state.threads;
if (e.target.checked) {
threads += "," + e.target.value;
} else {
threads = threadTextToList(threads)
.filter(thread => thread !== e.target.value)
.join(",");
}
background.adjustState({ threads });
renderState(background.state);
});
}
/**
* Clean up the thread list string into a list of values.
* @param string threads, comma separated values.
* @return Array list of thread names
*/
function threadTextToList(threads) {
return (
threads
// Split on commas
.split(",")
// Clean up any extraneous whitespace
.map(string => string.trim())
// Filter out any blank strings
.filter(string => string)
);
}
function makeExponentialScale(rangeStart, rangeEnd) {
const startExp = Math.log(rangeStart);
const endExp = Math.log(rangeEnd);
const fromFractionToValue = frac =>
Math.exp((1 - frac) * startExp + frac * endExp);
const fromValueToFraction = value =>
(Math.log(value) - startExp) / (endExp - startExp);
const fromFractionToSingleDigitValue = frac => {
return +fromFractionToValue(frac).toPrecision(1);
};
return {
fromFractionToValue,
fromValueToFraction,
fromFractionToSingleDigitValue,
};
}
const UNITS = ["B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
function prettyBytes(num) {
if (!Number.isFinite(num)) {
throw new TypeError(
`Expected a finite number, got ${typeof num}: ${num}`
);
}
const neg = num < 0;
if (neg) {
num = -num;
}
if (num < 1) {
return (neg ? "-" : "") + num + " B";
}
const exponent = Math.min(
Math.floor(Math.log(num) / Math.log(1000)),
UNITS.length - 1
);
const numStr = Number((num / Math.pow(1000, exponent)).toPrecision(3));
const unit = UNITS[exponent];
return (neg ? "-" : "") + numStr + " " + unit;
}
module.exports = {
initializePopup,
};

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

@ -2,5 +2,5 @@
- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="context-fill" d="M10.85 6.85a.5.5 0 0 0-.7-.7l-2.5 2.5.7.7 2.5-2.5zM8 10a1 1 0 1 0 0-2 1 1 0 0 0 0 2zM5 1a1 1 0 0 1 1-1h4a1 1 0 1 1 0 2H6a1 1 0 0 1-1-1zM8 4a5 5 0 1 0 0 10A5 5 0 0 0 8 4zM1 9a7 7 0 1 1 14 0A7 7 0 0 1 1 9z"/>
<path fill="context-fill" fill-opacity="context-fill-opacity" d="M10.85 6.85a.5.5 0 0 0-.7-.7l-2.5 2.5.7.7 2.5-2.5zM8 10a1 1 0 1 0 0-2 1 1 0 0 0 0 2zM5 1a1 1 0 0 1 1-1h4a1 1 0 1 1 0 2H6a1 1 0 0 1-1-1zM8 4a5 5 0 1 0 0 10A5 5 0 0 0 8 4zM1 9a7 7 0 1 1 14 0A7 7 0 0 1 1 9z"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 541 B

После

Ширина:  |  Высота:  |  Размер: 577 B

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

@ -129,6 +129,18 @@ DevToolsLoader.prototype = {
return this.require.apply(this, arguments);
},
/**
* A dummy version of lazyRequireGetter, in case a provider hasn't been chosen yet when
* this is first called. This will then be replaced by the real version.
* @see setProvider
*/
lazyRequireGetter: function() {
if (!this._provider) {
this._loadProvider();
}
return this.lazyRequireGetter.apply(this, arguments);
},
/**
* Return true if |id| refers to something requiring help from a
* loader plugin.

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

@ -3117,7 +3117,6 @@ exports.CSS_PROPERTIES = {
"shape-outside",
"touch-action",
"-webkit-line-clamp",
"color",
"column-width",
"column-count",
"column-fill",
@ -3163,6 +3162,7 @@ exports.CSS_PROPERTIES = {
"empty-cells",
"caption-side",
"border-spacing",
"color",
"line-height",
"text-transform",
"hyphens",

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

@ -13,6 +13,7 @@
* - Inject the wrench icon in toolbar customization, which is used
* by the "Web Developer" list displayed in the hamburger menu,
* - Register the JSON Viewer protocol handler.
* - Inject the profiler recording button in toolbar customization.
*
* Only once any of these entry point is fired, this module ensures starting
* core modules like 'devtools-browser.js' that hooks the browser windows
@ -29,6 +30,7 @@ const kDebuggerPrefs = [
const DEVTOOLS_ENABLED_PREF = "devtools.enabled";
const DEVTOOLS_POLICY_DISABLED_PREF = "devtools.policy.disabled";
const PROFILER_POPUP_ENABLED_PREF = "devtools.performance.popup.enabled";
const { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
@ -42,6 +44,8 @@ ChromeUtils.defineModuleGetter(this, "CustomizableWidgets",
"resource:///modules/CustomizableWidgets.jsm");
ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
ChromeUtils.defineModuleGetter(this, "ProfilerMenuButton",
"resource://devtools/client/performance-new/popup/menu-button.jsm");
// We don't want to spend time initializing the full loader here so we create
// our own lazy require.
@ -182,12 +186,47 @@ XPCOMUtils.defineLazyGetter(this, "KeyShortcuts", function() {
});
}
if (isProfilerButtonEnabled()) {
shortcuts.push(...getProfilerKeyShortcuts());
}
return shortcuts;
});
function getProfilerKeyShortcuts() {
return [
// Start/stop the profiler
{
id: "profilerStartStop",
shortcut: KeyShortcutsBundle.GetStringFromName("profilerStartStop.commandkey"),
modifiers: "control,shift",
},
// Capture a profile
{
id: "profilerCapture",
shortcut: KeyShortcutsBundle.GetStringFromName("profilerCapture.commandkey"),
modifiers: "control,shift",
},
];
}
/**
* Instead of loading the ProfilerMenuButton.jsm file, provide an independent check
* to see if it is turned on.
*/
function isProfilerButtonEnabled() {
return Services.prefs.getBoolPref(PROFILER_POPUP_ENABLED_PREF, false);
}
XPCOMUtils.defineLazyGetter(this, "ProfilerPopupBackground", function() {
return ChromeUtils.import(
"resource://devtools/client/performance-new/popup/background.jsm");
});
function DevToolsStartup() {
this.onEnabledPrefChanged = this.onEnabledPrefChanged.bind(this);
this.onWindowReady = this.onWindowReady.bind(this);
this.toggleProfilerKeyShortcuts = this.toggleProfilerKeyShortcuts.bind(this);
}
DevToolsStartup.prototype = {
@ -217,6 +256,12 @@ DevToolsStartup.prototype = {
*/
developerToggleCreated: false,
/**
* Flag that indicates if the profiler recording popup was already added to
* customizableUI.
*/
profilerRecordingButtonCreated: false,
isDisabledByPolicy: function() {
return Services.prefs.getBoolPref(DEVTOOLS_POLICY_DISABLED_PREF, false);
},
@ -236,12 +281,16 @@ DevToolsStartup.prototype = {
// Only top level Firefox Windows fire a browser-delayed-startup-finished event
Services.obs.addObserver(this.onWindowReady, "browser-delayed-startup-finished");
if (AppConstants.MOZ_DEV_EDITION && !this.isDisabledByPolicy()) {
// On DevEdition, the developer toggle is displayed by default in the navbar area
// and should be created before the first paint.
if (!this.isDisabledByPolicy()) {
if (AppConstants.MOZ_DEV_EDITION) {
// On DevEdition, the developer toggle is displayed by default in the navbar
// area and should be created before the first paint.
this.hookDeveloperToggle();
}
this.hookProfilerRecordingButton();
}
// Update menu items when devtools.enabled changes.
Services.prefs.addObserver(DEVTOOLS_ENABLED_PREF, this.onEnabledPrefChanged);
}
@ -360,6 +409,7 @@ DevToolsStartup.prototype = {
// initialized before the first browser-delayed-startup-finished event is received.
// We use a dedicated flag because we still need to hook the developer toggle.
this.hookDeveloperToggle();
this.hookProfilerRecordingButton();
// The developer menu hook only needs to be added if devtools have not been
// initialized yet.
@ -455,6 +505,22 @@ DevToolsStartup.prototype = {
this.developerToggleCreated = true;
},
/**
* Dynamically register a profiler recording button in the
* customization menu. You can use this button by right clicking
* on Firefox toolbar and dragging it from the customization panel
* to the toolbar. (i.e. this isn't displayed by default to users.)
*/
hookProfilerRecordingButton() {
if (this.profilerRecordingButtonCreated) {
return;
}
this.profilerRecordingButtonCreated = true;
if (isProfilerButtonEnabled()) {
ProfilerMenuButton.initialize();
}
},
/*
* We listen to the "Web Developer" system menu, which is under "Tools" main item.
* This menu item is hardcoded empty in Firefox UI. We listen for its opening to
@ -579,20 +645,90 @@ DevToolsStartup.prototype = {
const keyset = doc.createXULElement("keyset");
keyset.setAttribute("id", "devtoolsKeyset");
for (const key of KeyShortcuts) {
const xulKey = this.createKey(doc, key, () => this.onKey(window, key));
keyset.appendChild(xulKey);
}
this.attachKeys(doc, KeyShortcuts, keyset);
// Appending a <key> element is not always enough. The <keyset> needs
// to be detached and reattached to make sure the <key> is taken into
// account (see bug 832984).
const mainKeyset = doc.getElementById("mainKeyset");
mainKeyset.parentNode.insertBefore(keyset, mainKeyset);
// Watch for the profiler to enable or disable the profiler popup, then toggle
// the keyboard shortcuts on and off.
Services.prefs.addObserver(PROFILER_POPUP_ENABLED_PREF,
this.toggleProfilerKeyShortcuts);
},
/**
* This method attaches on the key elements to the devtools keyset.
*/
attachKeys(doc, keyShortcuts, keyset = doc.getElementById("devtoolsKeyset")) {
const window = doc.defaultView;
for (const key of keyShortcuts) {
const xulKey = this.createKey(doc, key, () => this.onKey(window, key));
keyset.appendChild(xulKey);
}
},
/**
* This method removes keys from the devtools keyset.
*/
removeKeys(doc, keyShortcuts) {
for (const key of keyShortcuts) {
const keyElement = doc.getElementById(this.getKeyElementId(key));
if (keyElement) {
keyElement.remove();
}
}
},
/**
* We only want to have the keyboard shortcuts active when the menu button is on.
* This function either adds or removes the elements.
*/
toggleProfilerKeyShortcuts() {
const isEnabled = isProfilerButtonEnabled();
const profilerKeyShortcuts = getProfilerKeyShortcuts();
for (const { document } of Services.wm.getEnumerator(null)) {
const devtoolsKeyset = document.getElementById("devtoolsKeyset");
const mainKeyset = document.getElementById("mainKeyset");
if (!devtoolsKeyset || !mainKeyset) {
// There may not be devtools keyset on this window.
continue;
}
if (isEnabled) {
this.attachKeys(document, profilerKeyShortcuts);
} else {
this.removeKeys(document, profilerKeyShortcuts);
}
// Appending a <key> element is not always enough. The <keyset> needs
// to be detached and reattached to make sure the <key> is taken into
// account (see bug 832984).
mainKeyset.parentNode.insertBefore(devtoolsKeyset, mainKeyset);
}
if (!isEnabled) {
// Ensure the profiler isn't left profiling in the background.
ProfilerPopupBackground.stopProfiler();
}
},
async onKey(window, key) {
try {
// The profiler doesn't care if DevTools is loaded, so provide a quick check
// first to bail out of checking if DevTools is available.
switch (key.id) {
case "profilerStartStop": {
ProfilerPopupBackground.toggleProfiler();
return;
}
case "profilerCapture": {
ProfilerPopupBackground.captureProfile();
return;
}
}
if (!Services.prefs.getBoolPref(DEVTOOLS_ENABLED_PREF)) {
const id = key.toolId || key.id;
this.openInstallPage("KeyShortcut", id);
@ -610,13 +746,23 @@ DevToolsStartup.prototype = {
}
},
getKeyElementId({ id, toolId }) {
return "key_" + (id || toolId);
},
// Create a <xul:key> DOM Element
createKey(doc, { id, toolId, shortcut, modifiers: mod }, oncommand) {
createKey(doc, key, oncommand) {
const { shortcut, modifiers: mod } = key;
const k = doc.createXULElement("key");
k.id = "key_" + (id || toolId);
k.id = this.getKeyElementId(key);
if (shortcut.startsWith("VK_")) {
k.setAttribute("keycode", shortcut);
if (shortcut.match(/^VK_\d$/)) {
// Add the event keydown attribute to ensure that shortcuts work for combinations
// such as ctrl shift 1.
k.setAttribute("event", "keydown");
}
} else {
k.setAttribute("key", shortcut);
}

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

@ -61,3 +61,11 @@ dom.commandkey=W
# LOCALIZATION NOTE (accessibilityF12.commandkey):
# Key pressed to open a toolbox with the accessibility panel selected
accessibilityF12.commandkey=VK_F12
# LOCALIZATION NOTE (profilerStartStop.commandkey):
# Key pressed to start or stop the performance profiler
profilerStartStop.commandkey=VK_1
# LOCALIZATION NOTE (profilerCapture.commandkey):
# Key pressed to capture a recorded performance profile
profilerCapture.commandkey=VK_2

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

@ -4104,7 +4104,8 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
formatStrCount = 1;
errorDescriptionID = "dnsNotFound2";
error = "dnsNotFound";
} else if (NS_ERROR_CONNECTION_REFUSED == aError) {
} else if (NS_ERROR_CONNECTION_REFUSED == aError ||
NS_ERROR_PROXY_BAD_GATEWAY == aError) {
NS_ENSURE_ARG_POINTER(aURI);
addHostPort = true;
error = "connectionFailure";
@ -4112,7 +4113,8 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
NS_ENSURE_ARG_POINTER(aURI);
addHostPort = true;
error = "netInterrupt";
} else if (NS_ERROR_NET_TIMEOUT == aError) {
} else if (NS_ERROR_NET_TIMEOUT == aError ||
NS_ERROR_PROXY_GATEWAY_TIMEOUT == aError) {
NS_ENSURE_ARG_POINTER(aURI);
// Get the host
nsAutoCString host;
@ -4341,6 +4343,7 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
error = "proxyResolveFailure";
break;
case NS_ERROR_PROXY_CONNECTION_REFUSED:
case NS_ERROR_PROXY_AUTHENTICATION_FAILED:
// Proxy connection was refused.
error = "proxyConnectFailure";
break;
@ -6935,15 +6938,18 @@ nsresult nsDocShell::EndPageLoad(nsIWebProgress* aProgress,
aStatus == NS_ERROR_CONNECTION_REFUSED ||
aStatus == NS_ERROR_UNKNOWN_PROXY_HOST ||
aStatus == NS_ERROR_PROXY_CONNECTION_REFUSED ||
aStatus == NS_ERROR_PROXY_AUTHENTICATION_FAILED ||
aStatus == NS_ERROR_BLOCKED_BY_POLICY) &&
(isTopFrame || UseErrorPages())) {
DisplayLoadError(aStatus, url, nullptr, aChannel);
} else if (aStatus == NS_ERROR_NET_TIMEOUT ||
aStatus == NS_ERROR_PROXY_GATEWAY_TIMEOUT ||
aStatus == NS_ERROR_REDIRECT_LOOP ||
aStatus == NS_ERROR_UNKNOWN_SOCKET_TYPE ||
aStatus == NS_ERROR_NET_INTERRUPT ||
aStatus == NS_ERROR_NET_RESET || aStatus == NS_ERROR_OFFLINE ||
aStatus == NS_ERROR_MALWARE_URI ||
aStatus == NS_ERROR_NET_RESET ||
aStatus == NS_ERROR_PROXY_BAD_GATEWAY ||
aStatus == NS_ERROR_OFFLINE || aStatus == NS_ERROR_MALWARE_URI ||
aStatus == NS_ERROR_PHISHING_URI ||
aStatus == NS_ERROR_UNWANTED_URI ||
aStatus == NS_ERROR_HARMFUL_URI ||

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

@ -16,7 +16,7 @@ using namespace mozilla;
nsDocShellEditorData::nsDocShellEditorData(nsIDocShell* aOwningDocShell)
: mDocShell(aOwningDocShell),
mDetachedEditingState(nsIHTMLDocument::eOff),
mDetachedEditingState(Document::EditingState::eOff),
mMakeEditable(false),
mIsDetached(false),
mDetachedMakeEditable(false) {
@ -111,10 +111,7 @@ nsresult nsDocShellEditorData::DetachFromWindow() {
mMakeEditable = false;
nsCOMPtr<dom::Document> doc = domWindow->GetDoc();
nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(doc);
if (htmlDoc) {
mDetachedEditingState = htmlDoc->GetEditingState();
}
mDetachedEditingState = doc->GetEditingState();
mDocShell = nullptr;
@ -133,10 +130,7 @@ nsresult nsDocShellEditorData::ReattachToWindow(nsIDocShell* aDocShell) {
mMakeEditable = mDetachedMakeEditable;
RefPtr<dom::Document> doc = domWindow->GetDoc();
nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(doc);
if (htmlDoc) {
htmlDoc->SetEditingState(mDetachedEditingState);
}
doc->SetEditingState(mDetachedEditingState);
return NS_OK;
}

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

@ -12,7 +12,7 @@
#include "mozilla/HTMLEditor.h"
#include "mozilla/RefPtr.h"
#include "nsIHTMLDocument.h"
#include "mozilla/dom/Document.h"
class nsIDocShell;
class nsEditingSession;
@ -47,7 +47,7 @@ class nsDocShellEditorData {
// Backup for the corresponding nsIHTMLDocument's editing state while
// the editor is detached.
nsIHTMLDocument::EditingState mDetachedEditingState;
mozilla::dom::Document::EditingState mDetachedEditingState;
// Indicates whether to make an editor after a url load.
bool mMakeEditable;

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

@ -13,6 +13,9 @@
#include "mozilla/Telemetry.h"
#include "mozilla/Unused.h"
#include "mozilla/XorShift128PlusRNG.h"
#include "mozilla/ipc/IPCStreamUtils.h"
using mozilla::ipc::AutoIPCStream;
static LazyLogModule gContentBlockingLog("ContentBlockingLog");
#define LOG(fmt, ...) \
@ -109,13 +112,43 @@ static void ReportOriginSingleHash(OriginMetricID aId,
nsCString(aOrigin));
}
void ContentBlockingLog::ReportLog() {
void ContentBlockingLog::ReportLog(nsIPrincipal* aFirstPartyPrincipal) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aFirstPartyPrincipal);
if (!StaticPrefs::browser_contentblocking_database_enabled()) {
return;
}
if (mLog.IsEmpty()) {
return;
}
dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
if (NS_WARN_IF(!contentChild)) {
return;
}
nsAutoCString json = Stringify();
nsCOMPtr<nsIInputStream> stream;
nsresult rv = NS_NewCStringInputStream(getter_AddRefs(stream), json);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
AutoIPCStream ipcStream;
ipcStream.Serialize(stream, contentChild);
Unused << contentChild->SendReportContentBlockingLog(
IPC::Principal(aFirstPartyPrincipal), ipcStream.TakeValue());
}
void ContentBlockingLog::ReportOrigins() {
if (!IsReportingEnabled()) {
return;
}
LOG("ContentBlockingLog::ReportLog [this=%p]", this);
LOG("ContentBlockingLog::ReportOrigins [this=%p]", this);
const bool testMode =
StaticPrefs::telemetry_origin_telemetry_test_mode_enabled();
OriginMetricID metricId =

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

@ -158,7 +158,8 @@ class ContentBlockingLog final {
}
}
void ReportLog();
void ReportOrigins();
void ReportLog(nsIPrincipal* aFirstPartyPrincipal);
nsAutoCString Stringify() {
nsAutoCString buffer;

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

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

@ -1550,6 +1550,68 @@ class Document : public nsINode,
// Sets the cache sizes for the current generation.
void SetCachedSizes(nsTabSizes* aSizes);
/**
* Should be called when an element's editable changes as a result of
* changing its contentEditable attribute/property.
*
* @param aElement the element for which the contentEditable
* attribute/property was changed
* @param aChange +1 if the contentEditable attribute/property was changed to
* true, -1 if it was changed to false
*/
nsresult ChangeContentEditableCount(nsIContent* aElement, int32_t aChange);
void DeferredContentEditableCountChange(nsIContent* aElement);
enum class EditingState : int8_t {
eTearingDown = -2,
eSettingUp = -1,
eOff = 0,
eDesignMode,
eContentEditable
};
/**
* Returns the editing state of the document (not editable, contentEditable or
* designMode).
*/
EditingState GetEditingState() const { return mEditingState; }
/**
* Returns whether the document is editable.
*/
bool IsEditingOn() const {
return GetEditingState() == EditingState::eDesignMode ||
GetEditingState() == EditingState::eContentEditable;
}
class MOZ_STACK_CLASS nsAutoEditingState {
public:
nsAutoEditingState(Document* aDoc, EditingState aState)
: mDoc(aDoc), mSavedState(aDoc->mEditingState) {
aDoc->mEditingState = aState;
}
~nsAutoEditingState() { mDoc->mEditingState = mSavedState; }
private:
RefPtr<Document> mDoc;
EditingState mSavedState;
};
friend class nsAutoEditingState;
/**
* Set the editing state of the document. Don't use this if you want
* to enable/disable editing, call EditingStateChanged() or
* SetDesignMode().
*/
nsresult SetEditingState(EditingState aState);
/**
* Called when this Document's editor is destroyed.
*/
void TearingDownEditor();
void SetKeyPressEventModel(uint16_t aKeyPressEventModel);
protected:
friend class nsUnblockOnloadEvent;
@ -1609,6 +1671,32 @@ class Document : public nsINode,
*/
void DisconnectNodeTree();
/**
* Like IsEditingOn(), but will flush as needed first.
*/
bool IsEditingOnAfterFlush();
/**
* MaybeDispatchCheckKeyPressEventModelEvent() dispatches
* "CheckKeyPressEventModel" event to check whether we should dispatch
* keypress events in confluent model or split model. This should be
* called only when mEditingState is changed to eDesignMode or
* eConentEditable at first time.
*/
void MaybeDispatchCheckKeyPressEventModelEvent();
/* Midas implementation */
nsCommandManager* GetMidasCommandManager();
nsresult TurnEditingOff();
// MOZ_CAN_RUN_SCRIPT_BOUNDARY because this is called from all sorts
// of places, and I'm pretty sure the exact ExecCommand call it
// makes cannot actually run script.
MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult EditingStateChanged();
void MaybeEditingStateChanged();
private:
class SelectorCacheKey {
public:
@ -2040,10 +2128,10 @@ class Document : public nsINode,
// content model or of style data, EndUpdate must be called afterward.
// To make this easy and painless, use the mozAutoDocUpdate helper class.
void BeginUpdate();
virtual void EndUpdate();
void EndUpdate();
uint32_t UpdateNestingLevel() { return mUpdateNestLevel; }
virtual void BeginLoad();
void BeginLoad();
virtual void EndLoad();
enum ReadyState {
@ -2344,7 +2432,7 @@ class Document : public nsINode,
* be rendered in "zombie state" until the next document is ready.
* The document should save form control state.
*/
virtual void RemovedFromDocShell();
void RemovedFromDocShell();
/**
* Get the layout history state that should be used to save and restore state
@ -2539,7 +2627,7 @@ class Document : public nsINode,
bool MayStartLayout() { return mMayStartLayout; }
virtual void SetMayStartLayout(bool aMayStartLayout);
void SetMayStartLayout(bool aMayStartLayout);
already_AddRefed<nsIDocumentEncoder> GetCachedEncoder();
@ -2773,7 +2861,7 @@ class Document : public nsINode,
/**
* Test whether we should be firing a load event for this document after a
* document.close(). This is public and on Document, instead of being private
* to nsHTMLDocument, because we need to go through the normal docloader logic
* to Document, because we need to go through the normal docloader logic
* for the readystate change to READYSTATE_COMPLETE with the normal timing and
* semantics of firing the load event; we just don't want to fire the load
* event if this tests true. So we need the docloader to be able to access
@ -3333,6 +3421,28 @@ class Document : public nsINode,
Nullable<WindowProxyHolder> GetDefaultView() const;
Element* GetActiveElement();
bool HasFocus(ErrorResult& rv) const;
void GetDesignMode(nsAString& aDesignMode);
void SetDesignMode(const nsAString& aDesignMode,
nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& rv);
void SetDesignMode(const nsAString& aDesignMode,
const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal,
mozilla::ErrorResult& rv);
MOZ_CAN_RUN_SCRIPT
bool ExecCommand(const nsAString& aCommandID, bool aDoShowUI,
const nsAString& aValue, nsIPrincipal& aSubjectPrincipal,
mozilla::ErrorResult& rv);
bool QueryCommandEnabled(const nsAString& aCommandID,
nsIPrincipal& aSubjectPrincipal,
mozilla::ErrorResult& rv);
bool QueryCommandIndeterm(const nsAString& aCommandID,
mozilla::ErrorResult& rv);
bool QueryCommandState(const nsAString& aCommandID, mozilla::ErrorResult& rv);
bool QueryCommandSupported(const nsAString& aCommandID,
mozilla::dom::CallerType aCallerType,
mozilla::ErrorResult& rv);
MOZ_CAN_RUN_SCRIPT
void QueryCommandValue(const nsAString& aCommandID, nsAString& aValue,
mozilla::ErrorResult& rv);
nsIHTMLCollection* Applets();
nsIHTMLCollection* Anchors();
TimeStamp LastFocusTime() const;
@ -4444,6 +4554,16 @@ class Document : public nsINode,
// allowed?
bool mTooDeepWriteRecursion : 1;
/**
* Temporary flag that is set in EndUpdate() to ignore
* MaybeEditingStateChanged() script runners from a nested scope.
*/
bool mPendingMaybeEditingStateChanged : 1;
// mHasBeenEditable is set to true when mEditingState is firstly set to
// eDesignMode or eContentEditable.
bool mHasBeenEditable : 1;
uint8_t mPendingFullscreenRequests;
uint8_t mXMLDeclarationBits;
@ -4460,6 +4580,9 @@ class Document : public nsINode,
// finishes processing that script.
uint32_t mWriteLevel;
uint32_t mContentEditableCount;
EditingState mEditingState;
// Compatibility mode
nsCompatibility mCompatMode;
@ -4657,6 +4780,8 @@ class Document : public nsINode,
RefPtr<DocGroup> mDocGroup;
RefPtr<nsCommandManager> mMidasCommandManager;
// The set of all the tracking script URLs. URLs are added to this set by
// calling NoteScriptTrackingStatus(). Currently we assume that a URL not
// existing in the set means the corresponding script isn't a tracking script.

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

@ -168,3 +168,11 @@ DOM4_MSG_DEF(InvalidAccessError, "synchronous XMLHttpRequests do not support tim
DOM4_MSG_DEF(EncodingError, "Node bound to inactive document.", NS_ERROR_DOM_IMAGE_INACTIVE_DOCUMENT)
DOM4_MSG_DEF(EncodingError, "Invalid image request.", NS_ERROR_DOM_IMAGE_INVALID_REQUEST)
DOM4_MSG_DEF(EncodingError, "Invalid encoded image data.", NS_ERROR_DOM_IMAGE_BROKEN)
/* Editing command errors. */
DOM4_MSG_DEF(InvalidStateError, "execCommand is only supported on HTML documents.", NS_ERROR_DOM_INVALID_STATE_DOCUMENT_EXEC_COMMAND)
DOM4_MSG_DEF(InvalidStateError, "queryCommandEnabled is only supported on HTML documents.", NS_ERROR_DOM_INVALID_STATE_DOCUMENT_QUERY_COMMAND_ENABLED)
DOM4_MSG_DEF(InvalidStateError, "queryCommandIndeterm is only supported on HTML documents.", NS_ERROR_DOM_INVALID_STATE_DOCUMENT_QUERY_COMMAND_INDETERM)
DOM4_MSG_DEF(InvalidStateError, "queryCommandState is only supported on HTML documents.", NS_ERROR_DOM_INVALID_STATE_DOCUMENT_QUERY_COMMAND_STATE)
DOM4_MSG_DEF(InvalidStateError, "queryCommandSupported is only supported on HTML documents.", NS_ERROR_DOM_INVALID_STATE_DOCUMENT_QUERY_COMMAND_SUPPORTED)
DOM4_MSG_DEF(InvalidStateError, "queryCommandValue is only supported on HTML documents.", NS_ERROR_DOM_INVALID_STATE_DOCUMENT_QUERY_COMMAND_VALUE)

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

@ -2241,10 +2241,11 @@ void nsFocusManager::UpdateCaret(bool aMoveCaretToFocus, bool aUpdateVisibility,
focusedDocShell->GetEditable(&isEditable);
if (isEditable) {
nsCOMPtr<nsIHTMLDocument> doc = do_QueryInterface(presShell->GetDocument());
Document* doc = presShell->GetDocument();
bool isContentEditableDoc =
doc && doc->GetEditingState() == nsIHTMLDocument::eContentEditable;
doc &&
doc->GetEditingState() == Document::EditingState::eContentEditable;
bool isFocusEditable = aContent && aContent->HasFlag(NODE_IS_EDITABLE);
if (!isContentEditableDoc || isFocusEditable) return;

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

@ -122,10 +122,14 @@ class CallbackObject : public nsISupports {
* This should only be called if you are certain that the return value won't
* be passed into a JS API function and that it won't be stored without being
* rooted (or otherwise signaling the stored value to the CC).
*
* Note that calling Reset() will also affect the value of any handle
* previously returned here. Don't call Reset() if a handle is still in use.
*/
JS::Handle<JSObject*> CallbackPreserveColor() const {
// Calling fromMarkedLocation() is safe because we trace our mCallback, and
// because the value of mCallback cannot change after if has been set.
// because the value of mCallback cannot change after if has been set
// (except for calling Reset() as described above).
return JS::Handle<JSObject*>::fromMarkedLocation(mCallback.address());
}
JS::Handle<JSObject*> CallbackGlobalPreserveColor() const {
@ -225,7 +229,8 @@ class CallbackObject : public nsISupports {
// Provide a way to clear this object's pointers to GC things after the
// callback has been run. Note that CallbackOrNull() will return null after
// this point. This should only be called if the object is known not to be
// used again.
// used again, and no handles (e.g. those returned by CallbackPreserveColor)
// are in use.
void Reset() { ClearJSReferences(); }
friend class mozilla::PromiseJobRunnable;

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

@ -1001,7 +1001,7 @@ bool CanvasRenderingContext2D::ParseColor(const nsAString& aString,
RefPtr<ComputedStyle> canvasStyle =
nsComputedDOMStyle::GetComputedStyle(mCanvasElement, nullptr);
if (canvasStyle) {
*aColor = canvasStyle->StyleColor()->mColor.ToColor();
*aColor = canvasStyle->StyleText()->mColor.ToColor();
}
// Beware that the presShell could be gone here.
}

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

@ -395,6 +395,12 @@ partial namespace ChromeUtils {
[ChromeOnly]
void resetLastExternalProtocolIframeAllowed();
/**
* Register a new toplevel window global actor. This method may only be
* called in the parent process. |name| must be globally unique.
*
* See JSWindowActor.webidl for WindowActorOptions fields documentation.
*/
[ChromeOnly, Throws]
void registerWindowActor(DOMString aName, optional WindowActorOptions aOptions);

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

@ -38,25 +38,31 @@ interface JSWindowActorChild {
[Throws]
readonly attribute nsIDocShell? docShell;
// NOTE: As this returns a window proxy, it may not be currently referencing
// the document associated with this JSWindowActor. Generally prefer using
// `document`.
/**
* NOTE: As this returns a window proxy, it may not be currently referencing
* the document associated with this JSWindowActor. Generally prefer using
* `document`.
*/
[Throws]
readonly attribute WindowProxy? contentWindow;
};
JSWindowActorChild implements JSWindowActor;
// WebIDL callback interface version of the nsIObserver interface for use when
// calling the observe method on JSWindowActors.
//
// NOTE: This isn't marked as ChromeOnly, as it has no interface object, and
// thus cannot be conditionally exposed.
/**
* WebIDL callback interface version of the nsIObserver interface for use when
* calling the observe method on JSWindowActors.
*
* NOTE: This isn't marked as ChromeOnly, as it has no interface object, and
* thus cannot be conditionally exposed.
*/
callback interface MozObserverCallback {
void observe(nsISupports subject, ByteString topic, DOMString? data);
};
// WebIDL callback interface calling the `willDestroy` and `didDestroy`
// method on JSWindowActors.
/**
* WebIDL callback interface calling the `willDestroy` and `didDestroy`
* method on JSWindowActors.
*/
[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
callback MozActorDestroyCallback = void();
@ -65,7 +71,7 @@ dictionary MozActorDestroyCallbacks {
[ChromeOnly] MozActorDestroyCallback didDestroy;
};
/*
/**
* Used by ChromeUtils.registerWindowActor() to register JS window actor.
*/
dictionary WindowActorOptions {
@ -104,7 +110,7 @@ dictionary WindowActorOptions {
};
dictionary WindowActorSidedOptions {
/** The module path which should be loaded for the actor on this side. */
/** The JSM path which should be loaded for the actor on this side. */
ByteString moduleURI;
};
@ -112,18 +118,20 @@ dictionary WindowActorChildOptions : WindowActorSidedOptions {
/**
* Events which this actor wants to be listening to. When these events fire,
* it will trigger actor creation, and then forward the event to the actor.
*
* NOTE: `once` option is not support due to we register listeners in a shared
* location.
*/
record<DOMString, AddEventListenerOptions> events;
/**
* Array of observer topics to listen to. A observer will be added for each
* An array of observer topics to listen to. An observer will be added for each
* topic in the list.
*
* Observers in the list much use the nsGlobalWindowInner object as their topic,
* and the events will only be dispatched to the corresponding window actor. If
* additional observer notifications are needed with different listening
* conditions, please file a bug in DOM requesting support for the subject
* required to be added to JS WindowActor objects.
* Observer notifications in the list use nsGlobalWindowInner object as their
* subject, and the events will only be dispatched to the corresponding window
* actor. If additional observer notification's subjects are needed, please
* file a bug for that.
**/
sequence<ByteString> observers;
};

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

@ -434,10 +434,9 @@ nsresult nsGenericHTMLElement::BindToTree(Document* aDocument,
if (HasFlag(NODE_IS_EDITABLE) && GetContentEditableValue() == eTrue &&
IsInComposedDoc()) {
nsCOMPtr<nsIHTMLDocument> htmlDocument =
do_QueryInterface(GetComposedDoc());
if (htmlDocument) {
htmlDocument->ChangeContentEditableCount(this, +1);
Document* doc = GetComposedDoc();
if (doc) {
doc->ChangeContentEditableCount(this, +1);
}
}
@ -460,10 +459,9 @@ void nsGenericHTMLElement::UnbindFromTree(bool aNullParent) {
RemoveFromNameTable();
if (GetContentEditableValue() == eTrue) {
nsCOMPtr<nsIHTMLDocument> htmlDocument =
do_QueryInterface(GetComposedDoc());
if (htmlDocument) {
htmlDocument->ChangeContentEditableCount(this, -1);
Document* doc = GetComposedDoc();
if (doc) {
doc->ChangeContentEditableCount(this, -1);
}
}
@ -2459,9 +2457,7 @@ void nsGenericHTMLElement::ChangeEditableState(int32_t aChange) {
}
if (aChange != 0) {
if (nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(document)) {
htmlDocument->ChangeContentEditableCount(this, aChange);
}
document->ChangeContentEditableCount(this, aChange);
}
if (document->HasFlag(NODE_IS_EDITABLE)) {

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

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

@ -66,9 +66,6 @@ class nsHTMLDocument : public mozilla::dom::Document, public nsIHTMLDocument {
bool aReset = true,
nsIContentSink* aSink = nullptr) override;
virtual void BeginLoad() override;
virtual void EndLoad() override;
protected:
virtual bool UseWidthDeviceWidthFallbackViewport() const override;
@ -88,41 +85,13 @@ class nsHTMLDocument : public mozilla::dom::Document, public nsIHTMLDocument {
virtual void AddedForm() override;
virtual void RemovedForm() override;
virtual int32_t GetNumFormsSynchronous() override;
virtual void TearingDownEditor() override;
virtual void SetIsXHTML(bool aXHTML) override {
mType = (aXHTML ? eXHTML : eHTML);
}
nsresult ChangeContentEditableCount(nsIContent* aElement,
int32_t aChange) override;
void DeferredContentEditableCountChange(nsIContent* aElement);
virtual EditingState GetEditingState() override { return mEditingState; }
class nsAutoEditingState {
public:
nsAutoEditingState(nsHTMLDocument* aDoc, EditingState aState)
: mDoc(aDoc), mSavedState(aDoc->mEditingState) {
aDoc->mEditingState = aState;
}
~nsAutoEditingState() { mDoc->mEditingState = mSavedState; }
private:
nsHTMLDocument* mDoc;
EditingState mSavedState;
};
friend class nsAutoEditingState;
void EndUpdate() override;
virtual void SetMayStartLayout(bool aMayStartLayout) override;
virtual nsresult SetEditingState(EditingState aState) override;
virtual nsresult Clone(mozilla::dom::NodeInfo*,
nsINode** aResult) const override;
virtual void RemovedFromDocShell() override;
using mozilla::dom::DocumentOrShadowRoot::GetElementById;
virtual void DocAddSizeOfExcludingThis(
@ -145,27 +114,6 @@ class nsHTMLDocument : public mozilla::dom::Document, public nsIHTMLDocument {
}
}
void GetSupportedNames(nsTArray<nsString>& aNames);
void GetDesignMode(nsAString& aDesignMode);
void SetDesignMode(const nsAString& aDesignMode,
nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& rv);
void SetDesignMode(const nsAString& aDesignMode,
const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal,
mozilla::ErrorResult& rv);
MOZ_CAN_RUN_SCRIPT
bool ExecCommand(const nsAString& aCommandID, bool aDoShowUI,
const nsAString& aValue, nsIPrincipal& aSubjectPrincipal,
mozilla::ErrorResult& rv);
bool QueryCommandEnabled(const nsAString& aCommandID,
nsIPrincipal& aSubjectPrincipal,
mozilla::ErrorResult& rv);
bool QueryCommandIndeterm(const nsAString& aCommandID,
mozilla::ErrorResult& rv);
bool QueryCommandState(const nsAString& aCommandID, mozilla::ErrorResult& rv);
bool QueryCommandSupported(const nsAString& aCommandID,
mozilla::dom::CallerType aCallerType);
MOZ_CAN_RUN_SCRIPT
void QueryCommandValue(const nsAString& aCommandID, nsAString& aValue,
mozilla::ErrorResult& rv);
void GetFgColor(nsAString& aFgColor);
void SetFgColor(const nsAString& aFgColor);
void GetLinkColor(nsAString& aLinkColor);
@ -194,8 +142,6 @@ class nsHTMLDocument : public mozilla::dom::Document, public nsIHTMLDocument {
void UserInteractionForTesting();
void SetKeyPressEventModel(uint16_t aKeyPressEventModel);
protected:
~nsHTMLDocument();
@ -205,11 +151,6 @@ class nsHTMLDocument : public mozilla::dom::Document, public nsIHTMLDocument {
static void DocumentWriteTerminationFunc(nsISupports* aRef);
/**
* Like IsEditingOn(), but will flush as needed first.
*/
bool IsEditingOnAfterFlush();
// A helper class to keep nsContentList objects alive for a short period of
// time. Note, when the final Release is called on an nsContentList object, it
// removes itself from MutationObserver list.
@ -256,45 +197,11 @@ class nsHTMLDocument : public mozilla::dom::Document, public nsIHTMLDocument {
static void TryFallback(int32_t& aCharsetSource,
NotNull<const Encoding*>& aEncoding);
/**
* MaybeDispatchCheckKeyPressEventModelEvent() dispatches
* "CheckKeyPressEventModel" event to check whether we should dispatch
* keypress events in confluent model or split model. This should be
* called only when mEditingState is changed to eDesignMode or
* eConentEditable at first time.
*/
void MaybeDispatchCheckKeyPressEventModelEvent();
// Load flags of the document's channel
uint32_t mLoadFlags;
bool mWarnedWidthHeight;
/* Midas implementation */
nsCommandManager* GetMidasCommandManager();
RefPtr<nsCommandManager> mMidasCommandManager;
nsresult TurnEditingOff();
// MOZ_CAN_RUN_SCRIPT_BOUNDARY because this is called from all sorts
// of places, and I'm pretty sure the exact ExecCommand call it
// makes cannot actually run script.
MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult EditingStateChanged();
void MaybeEditingStateChanged();
uint32_t mContentEditableCount;
EditingState mEditingState;
/**
* Temporary flag that is set in EndUpdate() to ignore
* MaybeEditingStateChanged() script runners from a nested scope.
*/
bool mPendingMaybeEditingStateChanged;
// mHasBeenEditable is set to true when mEditingState is firstly set to
// eDesignMode or eContentEditable.
bool mHasBeenEditable;
/**
* Set to true once we know that we are loading plain text content.
*/

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

@ -45,52 +45,6 @@ class nsIHTMLDocument : public nsISupports {
// not the rest?
virtual int32_t GetNumFormsSynchronous() = 0;
/**
* Should be called when an element's editable changes as a result of
* changing its contentEditable attribute/property.
*
* @param aElement the element for which the contentEditable
* attribute/property was changed
* @param aChange +1 if the contentEditable attribute/property was changed to
* true, -1 if it was changed to false
*/
virtual nsresult ChangeContentEditableCount(nsIContent* aElement,
int32_t aChange) = 0;
enum EditingState {
eTearingDown = -2,
eSettingUp = -1,
eOff = 0,
eDesignMode,
eContentEditable
};
/**
* Returns whether the document is editable.
*/
bool IsEditingOn() {
return GetEditingState() == eDesignMode ||
GetEditingState() == eContentEditable;
}
/**
* Returns the editing state of the document (not editable, contentEditable or
* designMode).
*/
virtual EditingState GetEditingState() = 0;
/**
* Set the editing state of the document. Don't use this if you want
* to enable/disable editing, call EditingStateChanged() or
* SetDesignMode().
*/
virtual nsresult SetEditingState(EditingState aState) = 0;
/**
* Called when this nsIHTMLDocument's editor is destroyed.
*/
virtual void TearingDownEditor() = 0;
virtual void SetIsXHTML(bool aXHTML) = 0;
};

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

@ -216,6 +216,7 @@
#include "nsPluginHost.h"
#include "nsPluginTags.h"
#include "nsIBlocklistService.h"
#include "nsITrackingDBService.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/StyleSheetInlines.h"
#include "nsICaptivePortalService.h"
@ -223,6 +224,8 @@
#include "nsIBidiKeyboard.h"
#include "nsLayoutStylesheetCache.h"
#include "MMPrinter.h"
#include "nsStreamUtils.h"
#include "nsIAsyncInputStream.h"
#include "mozilla/Sprintf.h"
@ -5497,6 +5500,26 @@ mozilla::ipc::IPCResult ContentParent::RecvRecordOrigin(
return IPC_OK();
}
mozilla::ipc::IPCResult ContentParent::RecvReportContentBlockingLog(
const Principal& aPrincipal, const IPCStream& aIPCStream) {
nsCOMPtr<nsITrackingDBService> trackingDBService =
do_GetService("@mozilla.org/tracking-db-service;1");
if (NS_WARN_IF(!trackingDBService)) {
return IPC_FAIL_NO_REASON(this);
}
nsCOMPtr<nsIPrincipal> principal(aPrincipal);
nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(aIPCStream);
nsCOMPtr<nsIAsyncInputStream> asyncStream;
nsresult rv = NS_MakeAsyncNonBlockingInputStream(stream.forget(),
getter_AddRefs(asyncStream));
if (NS_WARN_IF(NS_FAILED(rv))) {
return IPC_FAIL_NO_REASON(this);
}
trackingDBService->RecordContentBlockingLog(principal, asyncStream);
return IPC_OK();
}
//////////////////////////////////////////////////////////////////
// PURLClassifierParent

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

@ -1176,6 +1176,8 @@ class ContentParent final : public PContentParent,
const DiscardedData& aDiscardedData);
mozilla::ipc::IPCResult RecvRecordOrigin(const uint32_t& aMetricId,
const nsCString& aOrigin);
mozilla::ipc::IPCResult RecvReportContentBlockingLog(
const Principal& aPrincipal, const IPCStream& aIPCStream);
mozilla::ipc::IPCResult RecvBHRThreadHang(const HangDetails& aHangDetails);

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

@ -49,6 +49,7 @@ include protocol PSessionStorageObserver;
include DOMTypes;
include JavaScriptTypes;
include IPCBlob;
include IPCStream;
include PTabContext;
include URIParams;
include PluginTypes;
@ -1368,6 +1369,8 @@ parent:
async RecordDiscardedData(DiscardedData data);
async RecordOrigin(uint32_t metricId, nsCString origin);
async ReportContentBlockingLog(Principal firstPartyPrincipal, IPCStream aJSONStream);
sync GetA11yContentId() returns (uint32_t aContentId);
async A11yHandlerControl(uint32_t aPid,
IHandlerControlHolder aHandlerControl);

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

@ -39,7 +39,6 @@
#include "nsThreadUtils.h"
#include "nsIScriptChannel.h"
#include "mozilla/dom/Document.h"
#include "nsILoadInfo.h"
#include "nsIObjectInputStream.h"
#include "nsIObjectOutputStream.h"
#include "nsITextToSubURI.h"
@ -49,9 +48,9 @@
#include "mozilla/CycleCollectedJSContext.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/PopupBlocker.h"
#include "nsILoadInfo.h"
#include "nsContentSecurityManager.h"
#include "mozilla/LoadInfo.h"
#include "mozilla/Maybe.h"
#include "mozilla/ipc/URIUtils.h"
@ -160,8 +159,10 @@ nsresult nsJSThunk::EvaluateScript(
nsresult rv;
// CSP check: javascript: URIs disabled unless "inline" scripts are
// allowed.
nsCOMPtr<nsIContentSecurityPolicy> csp = loadInfo->GetCsp();
// allowed. Here we use the CSP of the thing that started the load,
// which is the CSPToInherit of the loadInfo.
nsCOMPtr<nsIContentSecurityPolicy> csp =
static_cast<mozilla::net::LoadInfo*>(loadInfo.get())->GetCSPToInherit();
if (csp) {
bool allowsInlineScript = true;
rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
@ -175,33 +176,26 @@ nsresult nsJSThunk::EvaluateScript(
&allowsInlineScript);
// return early if inline scripts are not allowed
if (!allowsInlineScript) {
if (NS_FAILED(rv) || !allowsInlineScript) {
return NS_ERROR_DOM_RETVAL_UNDEFINED;
}
}
// for document navigations we need to check the CSP of the previous document.
csp = nullptr;
mozilla::dom::Document* prevDoc = aOriginalInnerWindow->GetExtantDoc();
if (prevDoc) {
csp = prevDoc->GetCsp();
}
if (csp) {
bool allowsInlineScript = true;
rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
EmptyString(), // aNonce
true, // aParserCreated
nullptr, // aElement,
nullptr, // nsICSPEventListener
EmptyString(), // aContent
0, // aLineNumber
0, // aColumnNumber
&allowsInlineScript);
// return early if inline scripts are not allowed
if (!allowsInlineScript) {
return NS_ERROR_DOM_RETVAL_UNDEFINED;
}
}
// Based on the outcome of https://github.com/whatwg/html/issues/4651 we may
// want to also test against the CSP of the document we'll be running against
// (which is targetDoc below). If we do that, we should make sure to only do
// that test if targetDoc->NodePrincipal() subsumes
// loadInfo->TriggeringPrincipal(). If it doesn't, then someone
// more-privileged (our UI or an extension) started the load and the load
// should not be subject to the target document's CSP.
//
// The "more privileged" assumption is safe, because if the triggering
// principal does not subsume targetDoc->NodePrincipal() we won't run the
// script at all. More precisely, we test that "principal" subsumes the
// target's principal, but "principal" should never be higher-privilege than
// the triggering principal here: it's either the triggering principal, or the
// principal of the document we started the load against if the triggering
// principal is system.
// Get the global object we should be running on.
nsIScriptGlobalObject* global = GetGlobalObject(aChannel);
@ -209,16 +203,6 @@ nsresult nsJSThunk::EvaluateScript(
return NS_ERROR_FAILURE;
}
// Sandboxed document check: javascript: URI's are disabled
// in a sandboxed document unless 'allow-scripts' was specified.
mozilla::dom::Document* doc = aOriginalInnerWindow->GetExtantDoc();
if (doc && doc->HasScriptsBlockedBySandbox()) {
return NS_ERROR_DOM_RETVAL_UNDEFINED;
}
// Push our popup control state
AutoPopupStatePusher popupStatePusher(aPopupState);
// Make sure we still have the same inner window as we used to.
nsCOMPtr<nsPIDOMWindowOuter> win = do_QueryInterface(global);
nsPIDOMWindowInner* innerWin = win->GetCurrentInnerWindow();
@ -227,6 +211,17 @@ nsresult nsJSThunk::EvaluateScript(
return NS_ERROR_UNEXPECTED;
}
mozilla::dom::Document* targetDoc = innerWin->GetExtantDoc();
// Sandboxed document check: javascript: URI execution is disabled
// in a sandboxed document unless 'allow-scripts' was specified.
if (targetDoc && targetDoc->HasScriptsBlockedBySandbox()) {
return NS_ERROR_DOM_RETVAL_UNDEFINED;
}
// Push our popup control state
AutoPopupStatePusher popupStatePusher(aPopupState);
nsCOMPtr<nsIScriptGlobalObject> innerGlobal = do_QueryInterface(innerWin);
// So far so good: get the script context from its owner.

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

@ -12,6 +12,17 @@ function getTestServerPort() {
return port;
}
function getTestProxyPort() {
let portEnv = Cc["@mozilla.org/process/environment;1"]
.getService(Ci.nsIEnvironment).get("MOZHTTP2_PROXY_PORT");
let port = parseInt(portEnv, 10);
if (!Number.isFinite(port) || port < 1 || port > 65535) {
throw new Error(`Invalid port in MOZHTTP2_PROXY_PORT env var: ${portEnv}`);
}
info(`Using HTTP/2 proxy on port ${port}`);
return port;
}
function readFile(file) {
let fstream = Cc["@mozilla.org/network/file-input-stream;1"]
.createInstance(Ci.nsIFileInputStream);

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

@ -127,9 +127,8 @@ bool SVGCircleElement::GetGeometryBounds(
already_AddRefed<Path> SVGCircleElement::BuildPath(PathBuilder* aBuilder) {
float x, y, r;
MOZ_ASSERT(GetPrimaryFrame());
SVGGeometryProperty::ResolveAll<SVGT::Cx, SVGT::Cy, SVGT::R>(this, &x, &y,
&r);
SVGGeometryProperty::ResolveAllAllowFallback<SVGT::Cx, SVGT::Cy, SVGT::R>(
this, &x, &y, &r);
if (r <= 0.0f) {
return nullptr;

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

@ -29,6 +29,7 @@
#include "nsWhitespaceTokenizer.h"
#include "SVGAnimationElement.h"
#include "SVGAnimatedPreserveAspectRatio.h"
#include "SVGGeometryProperty.h"
#include "nsContentUtils.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Types.h"
@ -255,18 +256,10 @@ static DashState GetStrokeDashData(
void SVGContentUtils::GetStrokeOptions(AutoStrokeOptions* aStrokeOptions,
SVGElement* aElement,
ComputedStyle* aComputedStyle,
const ComputedStyle* aComputedStyle,
SVGContextPaint* aContextPaint,
StrokeOptionFlags aFlags) {
ComputedStyle* computedStyle;
if (aComputedStyle) {
computedStyle = aComputedStyle;
} else if (auto* f = aElement->GetPrimaryFrame()) {
computedStyle = f->Style();
} else {
return;
}
auto doCompute = [&](const ComputedStyle* computedStyle) {
const nsStyleSVG* styleSVG = computedStyle->StyleSVG();
bool checkedDashAndStrokeIsDashed = false;
@ -280,7 +273,8 @@ void SVGContentUtils::GetStrokeOptions(AutoStrokeOptions* aStrokeOptions,
return;
}
if (dashState == eContinuousStroke && aStrokeOptions->mDashPattern) {
// Prevent our caller from wasting time looking at a pattern without gaps:
// Prevent our caller from wasting time looking at a pattern without
// gaps:
aStrokeOptions->DiscardDashPattern();
}
checkedDashAndStrokeIsDashed = (dashState == eDashedStroke);
@ -305,8 +299,8 @@ void SVGContentUtils::GetStrokeOptions(AutoStrokeOptions* aStrokeOptions,
if (ShapeTypeHasNoCorners(aElement) && !checkedDashAndStrokeIsDashed) {
// Note: if aFlags == eIgnoreStrokeDashing then we may be returning the
// wrong linecap value here, since the actual linecap used on render in this
// case depends on whether the stroke is dashed or not.
// wrong linecap value here, since the actual linecap used on render in
// this case depends on whether the stroke is dashed or not.
aStrokeOptions->mLineCap = CapStyle::BUTT;
} else {
switch (styleSVG->mStrokeLinecap) {
@ -321,27 +315,38 @@ void SVGContentUtils::GetStrokeOptions(AutoStrokeOptions* aStrokeOptions,
break;
}
}
};
if (aComputedStyle) {
doCompute(aComputedStyle);
} else {
SVGGeometryProperty::DoForComputedStyle(aElement, doCompute);
}
}
Float SVGContentUtils::GetStrokeWidth(SVGElement* aElement,
ComputedStyle* aComputedStyle,
const ComputedStyle* aComputedStyle,
SVGContextPaint* aContextPaint) {
ComputedStyle* computedStyle;
if (aComputedStyle) {
computedStyle = aComputedStyle;
} else if (auto* f = aElement->GetPrimaryFrame()) {
computedStyle = f->Style();
} else {
return 0.0f;
}
Float res = 0.0;
auto doCompute = [&](ComputedStyle const* computedStyle) {
const nsStyleSVG* styleSVG = computedStyle->StyleSVG();
if (aContextPaint && styleSVG->StrokeWidthFromObject()) {
return aContextPaint->GetStrokeWidth();
res = aContextPaint->GetStrokeWidth();
return;
}
return SVGContentUtils::CoordToFloat(aElement, styleSVG->mStrokeWidth);
res = SVGContentUtils::CoordToFloat(aElement, styleSVG->mStrokeWidth);
};
if (aComputedStyle) {
doCompute(aComputedStyle);
} else {
SVGGeometryProperty::DoForComputedStyle(aElement, doCompute);
}
return res;
}
float SVGContentUtils::GetFontSize(Element* aElement) {

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

@ -151,7 +151,7 @@ class SVGContentUtils {
*/
static void GetStrokeOptions(AutoStrokeOptions* aStrokeOptions,
dom::SVGElement* aElement,
ComputedStyle* aComputedStyle,
const ComputedStyle* aComputedStyle,
mozilla::SVGContextPaint* aContextPaint,
StrokeOptionFlags aFlags = eAllStrokeOptions);
@ -165,7 +165,7 @@ class SVGContentUtils {
* "0", respectively.
*/
static Float GetStrokeWidth(dom::SVGElement* aElement,
ComputedStyle* aComputedStyle,
const ComputedStyle* aComputedStyle,
mozilla::SVGContextPaint* aContextPaint);
/*

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

@ -139,9 +139,9 @@ bool SVGEllipseElement::GetGeometryBounds(
already_AddRefed<Path> SVGEllipseElement::BuildPath(PathBuilder* aBuilder) {
float x, y, rx, ry;
MOZ_ASSERT(GetPrimaryFrame());
SVGGeometryProperty::ResolveAll<SVGT::Cx, SVGT::Cy, SVGT::Rx, SVGT::Ry>(
this, &x, &y, &rx, &ry);
SVGGeometryProperty::ResolveAllAllowFallback<SVGT::Cx, SVGT::Cy, SVGT::Rx,
SVGT::Ry>(this, &x, &y, &rx,
&ry);
if (rx <= 0.0f || ry <= 0.0f) {
return nullptr;

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

@ -13,6 +13,7 @@
#include "SVGAnimatedLength.h"
#include "SVGCircleElement.h"
#include "SVGEllipseElement.h"
#include "SVGGeometryProperty.h"
#include "SVGRectElement.h"
#include "mozilla/dom/SVGLengthBinding.h"
#include "mozilla/gfx/2D.h"
@ -133,15 +134,19 @@ FillRule SVGGeometryElement::GetFillRule() {
FillRule fillRule =
FillRule::FILL_WINDING; // Equivalent to StyleFillRule::Nonzero
if (auto* f = GetPrimaryFrame()) {
MOZ_ASSERT(f->StyleSVG()->mFillRule == StyleFillRule::Nonzero ||
f->StyleSVG()->mFillRule == StyleFillRule::Evenodd);
bool res = SVGGeometryProperty::DoForComputedStyle(
this, [&](const ComputedStyle* s) {
const auto* styleSVG = s->StyleSVG();
if (f->StyleSVG()->mFillRule == StyleFillRule::Evenodd) {
MOZ_ASSERT(styleSVG->mFillRule == StyleFillRule::Nonzero ||
styleSVG->mFillRule == StyleFillRule::Evenodd);
if (styleSVG->mFillRule == StyleFillRule::Evenodd) {
fillRule = FillRule::FILL_EVEN_ODD;
}
} else {
// ReportToConsole
});
if (!res) {
NS_WARNING("Couldn't get ComputedStyle for content in GetFillRule");
}

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

@ -10,6 +10,7 @@
#include "mozilla/dom/SVGElement.h"
#include "ComputedStyle.h"
#include "SVGAnimatedLength.h"
#include "nsComputedDOMStyle.h"
#include "nsGkAtoms.h"
#include "nsIFrame.h"
#include "nsSVGImageFrame.h"
@ -78,6 +79,7 @@ struct Ry {
namespace details {
template <class T>
using AlwaysFloat = float;
using dummy = int[];
using CtxDirectionType = decltype(SVGContentUtils::X);
@ -187,6 +189,25 @@ float ResolveWith(const ComputedStyle& aStyle, const SVGElement* aElement) {
typename Tag::ResolverType{});
}
template <class Func>
bool DoForComputedStyle(SVGElement* aElement, Func aFunc) {
if (const nsIFrame* f = aElement->GetPrimaryFrame()) {
aFunc(f->Style());
return true;
}
if (RefPtr<ComputedStyle> computedStyle =
nsComputedDOMStyle::GetComputedStyleNoFlush(aElement, nullptr)) {
aFunc(computedStyle.get());
return true;
}
return false;
}
#define SVGGEOMETRYPROPERTY_EVAL_ALL(expr) \
(void)details::dummy { 0, (static_cast<void>(expr), 0)... }
// To add support for new properties, or to handle special cases for
// existing properties, you can add a new tag in |Tags| and |ResolverTypes|
// namespace, then implement the behavior in |details::ResolveImpl|.
@ -194,13 +215,30 @@ template <class... Tags>
bool ResolveAll(const SVGElement* aElement,
details::AlwaysFloat<Tags>*... aRes) {
if (nsIFrame const* f = aElement->GetPrimaryFrame()) {
using dummy = int[];
(void)dummy{0, (*aRes = ResolveWith<Tags>(*f->Style(), aElement), 0)...};
SVGGEOMETRYPROPERTY_EVAL_ALL(*aRes =
ResolveWith<Tags>(*f->Style(), aElement));
return true;
}
return false;
}
template <class... Tags>
bool ResolveAllAllowFallback(SVGElement* aElement,
details::AlwaysFloat<Tags>*... aRes) {
bool res = DoForComputedStyle(aElement, [&](auto const* style) {
SVGGEOMETRYPROPERTY_EVAL_ALL(*aRes = ResolveWith<Tags>(*style, aElement));
});
if (res) {
return true;
}
SVGGEOMETRYPROPERTY_EVAL_ALL(*aRes = 0);
return false;
}
#undef SVGGEOMETRYPROPERTY_EVAL_ALL
nsCSSUnit SpecifiedUnitTypeToCSSUnit(uint8_t aSpecifiedUnit);
nsCSSPropertyID AttrEnumToCSSPropId(const SVGElement* aElement,
uint8_t aAttrEnum);

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

@ -270,9 +270,9 @@ already_AddRefed<Path> SVGImageElement::BuildPath(PathBuilder* aBuilder) {
// hit-testing against it. For that we just pretend to be a rectangle.
float x, y, width, height;
MOZ_ASSERT(GetPrimaryFrame());
SVGGeometryProperty::ResolveAll<SVGT::X, SVGT::Y, SVGT::Width, SVGT::Height>(
this, &x, &y, &width, &height);
SVGGeometryProperty::ResolveAllAllowFallback<SVGT::X, SVGT::Y, SVGT::Width,
SVGT::Height>(this, &x, &y,
&width, &height);
if (width <= 0 || height <= 0) {
return nullptr;

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

@ -10,6 +10,7 @@
#include "DOMSVGPathSeg.h"
#include "DOMSVGPathSegList.h"
#include "SVGGeometryProperty.h"
#include "gfx2DGlue.h"
#include "gfxPlatform.h"
#include "nsGkAtoms.h"
@ -260,17 +261,17 @@ already_AddRefed<Path> SVGPathElement::BuildPath(PathBuilder* aBuilder) {
uint8_t strokeLineCap = NS_STYLE_STROKE_LINECAP_BUTT;
Float strokeWidth = 0;
if (auto* f = GetPrimaryFrame()) {
const nsStyleSVG* style = f->StyleSVG();
SVGGeometryProperty::DoForComputedStyle(this, [&](const ComputedStyle* s) {
const nsStyleSVG* style = s->StyleSVG();
// Note: the path that we return may be used for hit-testing, and SVG
// exposes hit-testing of strokes that are not actually painted. For that
// reason we do not check for eStyleSVGPaintType_None or check the stroke
// opacity here.
if (style->mStrokeLinecap != NS_STYLE_STROKE_LINECAP_BUTT) {
strokeLineCap = style->mStrokeLinecap;
strokeWidth = SVGContentUtils::GetStrokeWidth(this, f->Style(), nullptr);
}
strokeWidth = SVGContentUtils::GetStrokeWidth(this, s, nullptr);
}
});
return mD.GetAnimValue().BuildPath(aBuilder, strokeLineCap, strokeWidth);
}

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

@ -170,10 +170,9 @@ bool SVGRectElement::GetGeometryBounds(Rect* aBounds,
void SVGRectElement::GetAsSimplePath(SimplePath* aSimplePath) {
float x, y, width, height, rx, ry;
MOZ_ASSERT(GetPrimaryFrame());
SVGGeometryProperty::ResolveAll<SVGT::X, SVGT::Y, SVGT::Width, SVGT::Height,
SVGT::Rx, SVGT::Ry>(this, &x, &y, &width,
&height, &rx, &ry);
SVGGeometryProperty::ResolveAllAllowFallback<
SVGT::X, SVGT::Y, SVGT::Width, SVGT::Height, SVGT::Rx, SVGT::Ry>(
this, &x, &y, &width, &height, &rx, &ry);
if (width <= 0 || height <= 0) {
aSimplePath->Reset();
@ -194,10 +193,9 @@ void SVGRectElement::GetAsSimplePath(SimplePath* aSimplePath) {
already_AddRefed<Path> SVGRectElement::BuildPath(PathBuilder* aBuilder) {
float x, y, width, height, rx, ry;
MOZ_ASSERT(GetPrimaryFrame());
SVGGeometryProperty::ResolveAll<SVGT::X, SVGT::Y, SVGT::Width, SVGT::Height,
SVGT::Rx, SVGT::Ry>(this, &x, &y, &width,
&height, &rx, &ry);
SVGGeometryProperty::ResolveAllAllowFallback<
SVGT::X, SVGT::Y, SVGT::Width, SVGT::Height, SVGT::Rx, SVGT::Ry>(
this, &x, &y, &width, &height, &rx, &ry);
if (width <= 0 || height <= 0) {
return nullptr;

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

@ -16,6 +16,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1474284
<path id="path1" stroke="#000" fill="none"
d="M 50,40
C 50,40 0,60 30,20"/>
<symbol font-size="10" width="20em" height="20em">
<rect id="r1" x="5em" y="6em" width="20%" height="30%" />
</symbol>
</svg>
<pre id="test">
@ -30,6 +33,10 @@ function expectValue(id, expected) {
function run() {
expectValue("path1", 55.19);
let r1 = document.getElementById("r1");
is(r1.getTotalLength(), 200, "getTotalLength() should work for display:none element");
SimpleTest.finish();
}

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

@ -160,15 +160,21 @@ partial interface Document {
readonly attribute WindowProxy? defaultView;
[Throws]
boolean hasFocus();
//(HTML only) attribute DOMString designMode;
//(HTML only)boolean execCommand(DOMString commandId);
//(HTML only)boolean execCommand(DOMString commandId, boolean showUI);
//(HTML only)boolean execCommand(DOMString commandId, boolean showUI, DOMString value);
//(HTML only)boolean queryCommandEnabled(DOMString commandId);
//(HTML only)boolean queryCommandIndeterm(DOMString commandId);
//(HTML only)boolean queryCommandState(DOMString commandId);
//(HTML only)boolean queryCommandSupported(DOMString commandId);
//(HTML only)DOMString queryCommandValue(DOMString commandId);
[CEReactions, SetterThrows, SetterNeedsSubjectPrincipal]
attribute DOMString designMode;
[CEReactions, Throws, NeedsSubjectPrincipal]
boolean execCommand(DOMString commandId, optional boolean showUI = false,
optional DOMString value = "");
[Throws, NeedsSubjectPrincipal]
boolean queryCommandEnabled(DOMString commandId);
[Throws]
boolean queryCommandIndeterm(DOMString commandId);
[Throws]
boolean queryCommandState(DOMString commandId);
[Throws, NeedsCallerType]
boolean queryCommandSupported(DOMString commandId);
[Throws]
DOMString queryCommandValue(DOMString commandId);
//(Not implemented)readonly attribute HTMLCollection commands;
// special event handler IDL attributes that only apply to Document objects
@ -608,3 +614,32 @@ partial interface Document {
[ChromeOnly]
void setRDMPaneOrientation(OrientationType type, float rotationAngle);
};
// Extension to give chrome JS the ability to specify a non-default keypress
// event model.
partial interface Document {
/**
* setKeyPressEventModel() is called when we need to check whether the web
* app requires specific keypress event model or not.
*
* @param aKeyPressEventModel Proper keypress event model for the web app.
* KEYPRESS_EVENT_MODEL_DEFAULT:
* Use default keypress event model. I.e., depending on
* "dom.keyboardevent.keypress.set_keycode_and_charcode_to_same_value"
* pref.
* KEYPRESS_EVENT_MODEL_SPLIT:
* Use split model. I.e, if keypress event inputs a character,
* keyCode should be 0. Otherwise, charCode should be 0.
* KEYPRESS_EVENT_MODEL_CONFLATED:
* Use conflated model. I.e., keyCode and charCode values of each
* keypress event should be set to same value.
*/
[ChromeOnly]
const unsigned short KEYPRESS_EVENT_MODEL_DEFAULT = 0;
[ChromeOnly]
const unsigned short KEYPRESS_EVENT_MODEL_SPLIT = 1;
[ChromeOnly]
const unsigned short KEYPRESS_EVENT_MODEL_CONFLATED = 2;
[ChromeOnly]
void setKeyPressEventModel(unsigned short aKeyPressEventModel);
};

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

@ -10,22 +10,6 @@ interface HTMLDocument : Document {
[Throws]
getter object (DOMString name);
[CEReactions, SetterThrows, SetterNeedsSubjectPrincipal]
attribute DOMString designMode;
[CEReactions, Throws, NeedsSubjectPrincipal]
boolean execCommand(DOMString commandId, optional boolean showUI = false,
optional DOMString value = "");
[Throws, NeedsSubjectPrincipal]
boolean queryCommandEnabled(DOMString commandId);
[Throws]
boolean queryCommandIndeterm(DOMString commandId);
[Throws]
boolean queryCommandState(DOMString commandId);
[NeedsCallerType]
boolean queryCommandSupported(DOMString commandId);
[Throws]
DOMString queryCommandValue(DOMString commandId);
[CEReactions] attribute [TreatNullAs=EmptyString] DOMString fgColor;
[CEReactions] attribute [TreatNullAs=EmptyString] DOMString linkColor;
[CEReactions] attribute [TreatNullAs=EmptyString] DOMString vlinkColor;
@ -61,29 +45,4 @@ partial interface HTMLDocument {
[ChromeOnly]
void userInteractionForTesting();
/**
* setKeyPressEventModel() is called when we need to check whether the web
* app requires specific keypress event model or not.
*
* @param aKeyPressEventModel Proper keypress event model for the web app.
* KEYPRESS_EVENT_MODEL_DEFAULT:
* Use default keypress event model. I.e., depending on
* "dom.keyboardevent.keypress.set_keycode_and_charcode_to_same_value"
* pref.
* KEYPRESS_EVENT_MODEL_SPLIT:
* Use split model. I.e, if keypress event inputs a character,
* keyCode should be 0. Otherwise, charCode should be 0.
* KEYPRESS_EVENT_MODEL_CONFLATED:
* Use conflated model. I.e., keyCode and charCode values of each
* keypress event should be set to same value.
*/
[ChromeOnly]
const unsigned short KEYPRESS_EVENT_MODEL_DEFAULT = 0;
[ChromeOnly]
const unsigned short KEYPRESS_EVENT_MODEL_SPLIT = 1;
[ChromeOnly]
const unsigned short KEYPRESS_EVENT_MODEL_CONFLATED = 2;
[ChromeOnly]
void setKeyPressEventModel(unsigned short aKeyPressEventModel);
};

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

@ -312,11 +312,8 @@ nsEditingSession::SetupEditorOnWindow(mozIDOMWindowProxy* aWindow) {
doc->FlushPendingNotifications(mozilla::FlushType::Frames);
if (mMakeWholeDocumentEditable) {
doc->SetEditableFlag(true);
nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(doc);
if (htmlDocument) {
// Enable usage of the execCommand API
htmlDocument->SetEditingState(nsIHTMLDocument::eDesignMode);
}
doc->SetEditingState(Document::EditingState::eDesignMode);
}
}
bool needHTMLController = false;
@ -358,7 +355,14 @@ nsEditingSession::SetupEditorOnWindow(mozIDOMWindowProxy* aWindow) {
if (mEditorStatus != eEditorCreationInProgress) {
RefPtr<ComposerCommandsUpdater> updater = mComposerCommandsUpdater;
updater->NotifyDocumentCreated();
return NS_ERROR_FAILURE;
// At this point we have made a final decision that we don't support
// editing the current document. This is an internal failure state, but
// we return NS_OK to avoid throwing an exception from the designMode
// setter for web compatibility. The document editing APIs will tell the
// developer if editing has been disabled because we're in a document type
// that doesn't support editing.
return NS_OK;
}
// Create editor and do other things
@ -504,8 +508,7 @@ nsEditingSession::TearDownEditorOnWindow(mozIDOMWindowProxy* aWindow) {
auto* window = nsPIDOMWindowOuter::From(aWindow);
RefPtr<Document> doc = window->GetDoc();
nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(doc);
bool stopEditing = htmlDoc && htmlDoc->IsEditingOn();
bool stopEditing = doc && doc->IsEditingOn();
if (stopEditing) {
RemoveWebProgressListener(window);
}
@ -515,7 +518,7 @@ nsEditingSession::TearDownEditorOnWindow(mozIDOMWindowProxy* aWindow) {
RefPtr<HTMLEditor> htmlEditor = docShell->GetHTMLEditor();
if (stopEditing) {
htmlDoc->TearingDownEditor();
doc->TearingDownEditor();
}
if (mComposerCommandsUpdater && htmlEditor) {
@ -537,10 +540,7 @@ nsEditingSession::TearDownEditorOnWindow(mozIDOMWindowProxy* aWindow) {
if (mMakeWholeDocumentEditable) {
doc->SetEditableFlag(false);
nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(doc);
if (htmlDocument) {
htmlDocument->SetEditingState(nsIHTMLDocument::eOff);
}
doc->SetEditingState(Document::EditingState::eOff);
}
}

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

@ -448,8 +448,7 @@ bool EditorBase::GetDesiredSpellCheckState() {
// Some of the page content might be editable and some not, if spellcheck=
// is explicitly set anywhere, so if there's anything editable on the page,
// return true and let the spellchecker figure it out.
nsCOMPtr<nsIHTMLDocument> doc =
do_QueryInterface(content->GetComposedDoc());
Document* doc = content->GetComposedDoc();
return doc && doc->IsEditingOn();
}

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

@ -629,7 +629,7 @@ nsresult HTMLEditor::GetTemporaryStyleForFocusedPositionedElement(
const uint8_t kBlackBgTrigger = 0xd0;
const auto& color = style->StyleColor()->mColor;
const auto& color = style->StyleText()->mColor;
if (color.red >= kBlackBgTrigger && color.green >= kBlackBgTrigger &&
color.blue >= kBlackBgTrigger) {
aReturn.AssignLiteral("black");

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

@ -383,12 +383,12 @@ nsresult HTMLEditRules::BeforeEdit(EditSubAction aEditSubAction,
}
// Stabilize the document against contenteditable count changes
nsHTMLDocument* htmlDoc = HTMLEditorRef().GetHTMLDocument();
if (NS_WARN_IF(!htmlDoc)) {
Document* doc = HTMLEditorRef().GetDocument();
if (NS_WARN_IF(!doc)) {
return NS_ERROR_FAILURE;
}
if (htmlDoc->GetEditingState() == nsIHTMLDocument::eContentEditable) {
htmlDoc->ChangeContentEditableCount(nullptr, +1);
if (doc->GetEditingState() == Document::EditingState::eContentEditable) {
doc->ChangeContentEditableCount(nullptr, +1);
mRestoreContentEditableCount = true;
}
@ -432,12 +432,12 @@ nsresult HTMLEditRules::AfterEdit(EditSubAction aEditSubAction,
// Reset the contenteditable count to its previous value
if (mRestoreContentEditableCount) {
nsHTMLDocument* htmlDoc = HTMLEditorRef().GetHTMLDocument();
if (NS_WARN_IF(!htmlDoc)) {
Document* doc = HTMLEditorRef().GetDocument();
if (NS_WARN_IF(!doc)) {
return NS_ERROR_FAILURE;
}
if (htmlDoc->GetEditingState() == nsIHTMLDocument::eContentEditable) {
htmlDoc->ChangeContentEditableCount(nullptr, -1);
if (doc->GetEditingState() == Document::EditingState::eContentEditable) {
doc->ChangeContentEditableCount(nullptr, -1);
}
mRestoreContentEditableCount = false;
}

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

@ -481,7 +481,11 @@ class FullParseHandler {
FunctionSyntaxKind::ClassConstructor ||
node->scopeBody()->as<ClassMethod>().method().syntaxKind() ==
FunctionSyntaxKind::DerivedClassConstructor);
MOZ_ASSERT(!node->isEmptyScope());
// Check isEmptyScope instead of asserting, because this function must
// be idempotent: when parsing via asm.js, this function is called, then
// later, after asm.js parsing fails, this function is called again on
// the same scope. (See bug 1555979)
if (!node->isEmptyScope()) {
MOZ_ASSERT(node->scopeBindings()->length == 1);
MOZ_ASSERT(node->scopeBindings()->trailingNames[0].name() ==
cx->names().dotInitializers);
@ -489,6 +493,7 @@ class FullParseHandler {
}
}
}
}
UnaryNodeType newInitialYieldExpression(uint32_t begin, Node gen) {
TokenPos pos(begin, begin + 1);

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

@ -0,0 +1,8 @@
(function() {
"use asm";
function f() {
class X {
constructor() {};
}
}
})();

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

@ -145,6 +145,9 @@ XPC_MSG_DEF(NS_ERROR_ALREADY_CONNECTED , "The connection is already
XPC_MSG_DEF(NS_ERROR_NOT_CONNECTED , "The connection does not exist")
XPC_MSG_DEF(NS_ERROR_CONNECTION_REFUSED , "The connection was refused")
XPC_MSG_DEF(NS_ERROR_PROXY_CONNECTION_REFUSED , "The connection to the proxy server was refused")
XPC_MSG_DEF(NS_ERROR_PROXY_AUTHENTICATION_FAILED , "The proxy requires authentication")
XPC_MSG_DEF(NS_ERROR_PROXY_BAD_GATEWAY , "The request failed on the proxy")
XPC_MSG_DEF(NS_ERROR_PROXY_GATEWAY_TIMEOUT , "The request timed out on the proxy")
XPC_MSG_DEF(NS_ERROR_NET_TIMEOUT , "The connection has timed out")
XPC_MSG_DEF(NS_ERROR_OFFLINE , "The requested action could not be completed in the offline state")
XPC_MSG_DEF(NS_ERROR_PORT_ACCESS_NOT_ALLOWED , "Establishing a connection to an unsafe or otherwise banned port was prohibited")

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

@ -1191,7 +1191,7 @@ class PresShell final : public nsStubDocumentObserver,
void SetKeyPressEventModel(uint16_t aKeyPressEventModel) {
mForceUseLegacyKeyCodeAndCharCodeValues |=
aKeyPressEventModel ==
dom::HTMLDocument_Binding::KEYPRESS_EVENT_MODEL_SPLIT;
dom::Document_Binding::KEYPRESS_EVENT_MODEL_SPLIT;
}
bool AddRefreshObserver(nsARefreshObserver* aObserver, FlushType aFlushType);

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

@ -1494,7 +1494,7 @@ void nsComboboxControlFrame::PaintFocus(DrawTarget& aDrawTarget, nsPoint aPt) {
StrokeOptions strokeOptions;
nsLayoutUtils::InitDashPattern(strokeOptions, StyleBorderStyle::Dotted);
ColorPattern color(ToDeviceColor(StyleColor()->mColor));
ColorPattern color(ToDeviceColor(StyleText()->mColor));
nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
clipRect.width -= onePixel;
clipRect.height -= onePixel;

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

@ -688,7 +688,7 @@ Maybe<BulletRenderer> nsBulletFrame::CreateBulletRenderer(
}
}
nscolor color = nsLayoutUtils::GetColor(this, &nsStyleColor::mColor);
nscolor color = nsLayoutUtils::GetColor(this, &nsStyleText::mColor);
DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
int32_t appUnitsPerDevPixel = PresContext()->AppUnitsPerDevPixel();

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

@ -634,9 +634,9 @@ void nsCanvasFrame::PaintFocus(DrawTarget* aDrawTarget, nsPoint aPt) {
// XXX use the root frame foreground color, but should we find BODY frame
// for HTML documents?
nsIFrame* root = mFrames.FirstChild();
const nsStyleColor* color = root ? root->StyleColor() : StyleColor();
const auto* text = root ? root->StyleText() : StyleText();
nsCSSRendering::PaintFocus(PresContext(), aDrawTarget, focusRect,
color->mColor.ToColor());
text->mColor.ToColor());
}
/* virtual */

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

@ -1181,7 +1181,7 @@ void nsImageFrame::DisplayAltText(nsPresContext* aPresContext,
const nsString& aAltText,
const nsRect& aRect) {
// Set font and color
aRenderingContext.SetColor(Color::FromABGR(StyleColor()->mColor.ToColor()));
aRenderingContext.SetColor(Color::FromABGR(StyleText()->mColor.ToColor()));
RefPtr<nsFontMetrics> fm =
nsLayoutUtils::GetInflatedFontMetricsForFrame(this);

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

@ -478,7 +478,7 @@ static void SetAnimatable(nsCSSPropertyID aProperty,
// We don't support color animation on the compositor yet so that we can
// resolve currentColor at this moment.
nscolor foreground =
aFrame->Style()->GetVisitedDependentColor(&nsStyleColor::mColor);
aFrame->Style()->GetVisitedDependentColor(&nsStyleText::mColor);
aAnimatable = aAnimationValue.GetColor(foreground);
break;
}

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

@ -129,7 +129,6 @@ nsChangeHint ComputedStyle::CalcStyleDifference(const ComputedStyle& aNewStyle,
DO_STRUCT_DIFFERENCE(TextReset);
DO_STRUCT_DIFFERENCE(Effects);
DO_STRUCT_DIFFERENCE(Background);
DO_STRUCT_DIFFERENCE(Color);
#undef DO_STRUCT_DIFFERENCE
#undef DO_STRUCT_DIFFERENCE_WITH_ARGS

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

@ -77,12 +77,12 @@ nscolor StyleColor::CalcColor(const StyleRGBA& aForegroundColor) const {
template <>
nscolor StyleColor::CalcColor(const ComputedStyle& aStyle) const {
// Common case that is numeric color, which is pure background, we
// can skip resolving StyleColor().
// can skip resolving StyleText().
// TODO(djg): Is this optimization worth it?
if (IsNumeric()) {
return AsNumeric().ToColor();
}
return CalcColor(aStyle.StyleColor()->mColor);
return CalcColor(aStyle.StyleText()->mColor);
}
template <>

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

@ -17,10 +17,9 @@
* before including this file.
*
* Note that, currently, there is a restriction that all fields in a
* style struct must have the same type.
* each entry must have the same type, otherwise you need two entries.
*/
STYLE_STRUCT(Color, (mColor))
STYLE_STRUCT(Background, (mBackgroundColor))
STYLE_STRUCT(Border, (mBorderTopColor,
mBorderRightColor,
@ -28,6 +27,7 @@ STYLE_STRUCT(Border, (mBorderTopColor,
mBorderLeftColor))
STYLE_STRUCT(Outline, (mOutlineColor))
STYLE_STRUCT(Column, (mColumnRuleColor))
STYLE_STRUCT(Text, (mColor))
STYLE_STRUCT(Text, (mTextEmphasisColor,
mWebkitTextFillColor,
mWebkitTextStrokeColor))

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

@ -1634,32 +1634,6 @@ nsChangeHint nsStyleTableBorder::CalcDifference(
}
}
// --------------------
// nsStyleColor
//
static StyleRGBA DefaultColor(const Document& aDocument) {
return StyleRGBA::FromColor(
PreferenceSheet::PrefsFor(aDocument).mDefaultColor);
}
nsStyleColor::nsStyleColor(const Document& aDocument)
: mColor(DefaultColor(aDocument)) {
MOZ_COUNT_CTOR(nsStyleColor);
}
nsStyleColor::nsStyleColor(const nsStyleColor& aSource)
: mColor(aSource.mColor) {
MOZ_COUNT_CTOR(nsStyleColor);
}
nsChangeHint nsStyleColor::CalcDifference(const nsStyleColor& aNewData) const {
if (mColor == aNewData.mColor) {
return nsChangeHint(0);
}
return nsChangeHint_RepaintFrame;
}
// --------------------
// nsStyleGradient
//
@ -3554,8 +3528,14 @@ nsChangeHint nsStyleTextReset::CalcDifference(
// nsStyleText
//
static StyleRGBA DefaultColor(const Document& aDocument) {
return StyleRGBA::FromColor(
PreferenceSheet::PrefsFor(aDocument).mDefaultColor);
}
nsStyleText::nsStyleText(const Document& aDocument)
: mTextTransform(StyleTextTransform::None()),
: mColor(DefaultColor(aDocument)),
mTextTransform(StyleTextTransform::None()),
mTextAlign(NS_STYLE_TEXT_ALIGN_START),
mTextAlignLast(NS_STYLE_TEXT_ALIGN_AUTO),
mTextJustify(StyleTextJustify::Auto),
@ -3588,7 +3568,8 @@ nsStyleText::nsStyleText(const Document& aDocument)
}
nsStyleText::nsStyleText(const nsStyleText& aSource)
: mTextTransform(aSource.mTextTransform),
: mColor(aSource.mColor),
mTextTransform(aSource.mTextTransform),
mTextAlign(aSource.mTextAlign),
mTextAlignLast(aSource.mTextAlignLast),
mTextJustify(aSource.mTextJustify),
@ -3680,6 +3661,10 @@ nsChangeHint nsStyleText::CalcDifference(const nsStyleText& aNewData) const {
return hint;
}
if (mColor != aNewData.mColor) {
hint |= nsChangeHint_RepaintFrame;
}
if (mTextEmphasisColor != aNewData.mTextEmphasisColor ||
mWebkitTextFillColor != aNewData.mWebkitTextFillColor ||
mWebkitTextStrokeColor != aNewData.mWebkitTextStrokeColor) {

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

@ -437,22 +437,6 @@ struct nsStyleImage {
mozilla::UniquePtr<nsStyleSides> mCropRect;
};
struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleColor {
explicit nsStyleColor(const mozilla::dom::Document&);
nsStyleColor(const nsStyleColor& aOther);
~nsStyleColor() { MOZ_COUNT_DTOR(nsStyleColor); }
void TriggerImageLoads(mozilla::dom::Document&, const nsStyleColor*) {}
const static bool kHasTriggerImageLoads = false;
nsChangeHint CalcDifference(const nsStyleColor& aNewData) const;
// Don't add ANY members to this struct! We can achieve caching in the rule
// tree (rather than the style tree) by letting color stay by itself! -dwh
//
// FIXME(emilio): Not sure having color in its own struct is worth it anymore.
mozilla::StyleRGBA mColor;
};
struct nsStyleImageLayers {
// Indices into kBackgroundLayerTable and kMaskLayerTable
enum {
@ -1283,6 +1267,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleText {
nsChangeHint CalcDifference(const nsStyleText& aNewData) const;
mozilla::StyleRGBA mColor;
mozilla::StyleTextTransform mTextTransform;
uint8_t mTextAlign; // NS_STYLE_TEXT_ALIGN_*
uint8_t mTextAlignLast; // NS_STYLE_TEXT_ALIGN_*

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

@ -33,7 +33,6 @@
// STYLE_STRUCT rather than including the file twice.
STYLE_STRUCT_INHERITED(Font)
STYLE_STRUCT_INHERITED(Color)
STYLE_STRUCT_INHERITED(List)
STYLE_STRUCT_INHERITED(Text)
STYLE_STRUCT_INHERITED(Visibility)

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

@ -600,7 +600,7 @@ nsresult nsFilterInstance::BuildPrimitivesForFilter(
// If we don't have a frame, use opaque black for shadows with unspecified
// shadow colors.
nscolor shadowFallbackColor =
mTargetFrame ? mTargetFrame->StyleColor()->mColor.ToColor()
mTargetFrame ? mTargetFrame->StyleText()->mColor.ToColor()
: NS_RGB(0, 0, 0);
nsCSSFilterInstance cssFilterInstance(

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

@ -284,7 +284,7 @@ void nsDisplayXULTextBox::Paint(nsDisplayListBuilder* aBuilder,
nsRect drawRect =
static_cast<nsTextBoxFrame*>(mFrame)->mTextDrawRect + ToReferenceFrame();
nsLayoutUtils::PaintTextShadow(mFrame, aCtx, drawRect, GetPaintRect(),
mFrame->StyleColor()->mColor.ToColor(),
mFrame->StyleText()->mColor.ToColor(),
PaintTextShadowCallback, (void*)this);
PaintTextToContext(aCtx, nsPoint(0, 0), nullptr);
@ -489,7 +489,7 @@ void nsTextBoxFrame::DrawText(gfxContext& aRenderingContext,
CalculateUnderline(refDrawTarget, *fontMet);
nscolor c = aOverrideColor ? *aOverrideColor : StyleColor()->mColor.ToColor();
nscolor c = aOverrideColor ? *aOverrideColor : StyleText()->mColor.ToColor();
ColorPattern color(ToDeviceColor(c));
aRenderingContext.SetColor(Color::FromABGR(c));

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

@ -3452,7 +3452,7 @@ ImgDrawResult nsTreeBodyFrame::PaintText(
textRect.Deflate(bp);
// Set our color.
ColorPattern color(ToDeviceColor(textContext->StyleColor()->mColor));
ColorPattern color(ToDeviceColor(textContext->StyleText()->mColor));
// Draw decorations.
StyleTextDecorationLine decorations =
@ -3490,7 +3490,7 @@ ImgDrawResult nsTreeBodyFrame::PaintText(
}
aRenderingContext.SetColor(
Color::FromABGR(textContext->StyleColor()->mColor.ToColor()));
Color::FromABGR(textContext->StyleText()->mColor.ToColor()));
nsLayoutUtils::DrawString(
this, *fontMet, &aRenderingContext, text.get(), text.Length(),
textRect.TopLeft() + nsPoint(0, baseline), cellContext);

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

@ -11,6 +11,7 @@ const {HistogramStopwatch} = ChromeUtils.import("resource://gre/modules/GeckoVie
const PAGE_LOAD_PROGRESS_PROBE =
new HistogramStopwatch("GV_PAGE_LOAD_PROGRESS_MS", content);
const PAGE_LOAD_PROBE = new HistogramStopwatch("GV_PAGE_LOAD_MS", content);
const PAGE_RELOAD_PROBE = new HistogramStopwatch("GV_PAGE_RELOAD_MS", content);
class GeckoViewProgressChild extends GeckoViewChildModule {
onInit() {
@ -45,15 +46,32 @@ class GeckoViewProgressChild extends GeckoViewChildModule {
debug `onStateChange: uri=${uri}`;
let isPageReload = false;
if (aWebProgress.loadType & Ci.nsIDocShell.LOAD_CMD_RELOAD) {
isPageReload = true;
}
if (aStateFlags & Ci.nsIWebProgressListener.STATE_START) {
if (!isPageReload) {
PAGE_LOAD_PROBE.start();
} else {
PAGE_RELOAD_PROBE.start();
}
ProgressTracker.start(uri);
} else if ((aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) &&
!aWebProgress.isLoadingDocument) {
if (!isPageReload) {
PAGE_LOAD_PROBE.finish();
} else {
PAGE_RELOAD_PROBE.finish();
}
ProgressTracker.stop();
} else if (aStateFlags & Ci.nsIWebProgressListener.STATE_REDIRECTING) {
if (!isPageReload) {
PAGE_LOAD_PROBE.start();
} else {
PAGE_RELOAD_PROBE.start();
}
ProgressTracker.start(uri);
}
}

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

@ -134,6 +134,11 @@ class GeckoViewNavigation extends GeckoViewModule {
});
break;
case "GeckoView:Reload":
// At the moment, GeckoView only supports one reload, which uses
// nsIWebNavigation.LOAD_FLAGS_NONE flag, and the telemetry doesn't
// do anything to differentiate reloads (i.e normal vs skip caches)
// So whenever we add more reload methods, please make sure the
// telemetry probe is adjusted
this.browser.reload();
break;
case "GeckoView:Stop":

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

@ -708,6 +708,13 @@ VARCACHE_PREF(
bool, true
)
VARCACHE_PREF(
Live,
"browser.contentblocking.database.enabled",
browser_contentblocking_database_enabled,
bool, true
)
// How many recent block/unblock actions per origins we remember in the
// Content Blocking log for each top-level window.
VARCACHE_PREF(

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

@ -5096,7 +5096,11 @@ pref("gfx.direct3d11.break-on-error", false);
// Prefer flipping between two buffers over copying from our back buffer
// to the OS.
#ifdef NIGHTLY_BUILD
pref("gfx.direct3d11.use-double-buffering", true);
#else
pref("gfx.direct3d11.use-double-buffering", false);
#endif
pref("layers.prefer-opengl", false);
#endif

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