diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 6c35057505bd..dc4e54f251f1 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -7992,7 +7992,7 @@ var ToolbarIconColor = { break; } - let toolbarSelector = "#navigator-toolbox > toolbar:not([collapsed=true])"; + let toolbarSelector = ".browser-toolbar:not([collapsed=true])"; if (AppConstants.platform == "macosx") toolbarSelector += ":not([type=menubar])"; diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul index c3b60cbd56a0..65c01c6778d6 100644 --- a/browser/base/content/browser.xul +++ b/browser/base/content/browser.xul @@ -672,7 +672,7 @@ xmlns="http://www.w3.org/1999/xhtml" { content.location = uri; }); @@ -108,7 +108,7 @@ add_task(async function() { "Check that http tab still in file content process after location change."); // Check that cross-origin load does break the affinity. - promiseLoad = BrowserTestUtils.browserLoaded(httpBrowser); + promiseLoad = BrowserTestUtils.browserLoaded(httpBrowser, false, TEST_CROSS_ORIGIN); httpBrowser.loadURI(TEST_CROSS_ORIGIN); await promiseLoad; await CheckBrowserNotInPid(httpBrowser, filePid, diff --git a/browser/base/content/test/tabs/browser_opened_file_tab_navigated_to_web.js b/browser/base/content/test/tabs/browser_opened_file_tab_navigated_to_web.js index cd62f78fae12..93a503eaf7cb 100644 --- a/browser/base/content/test/tabs/browser_opened_file_tab_navigated_to_web.js +++ b/browser/base/content/test/tabs/browser_opened_file_tab_navigated_to_web.js @@ -2,6 +2,7 @@ /* vim: set ft=javascript ts=2 et sw=2 tw=80: */ const TEST_FILE = "dummy_page.html"; +const WEB_ADDRESS = "http://example.org/"; // Test for bug 1321020. add_task(async function() { @@ -35,8 +36,8 @@ add_task(async function() { let openedBrowser = openedTab.linkedBrowser; // Ensure that new file:// tab can be navigated to web content. - openedBrowser.loadURI("http://example.org/"); - let href = await BrowserTestUtils.browserLoaded(openedBrowser); - is(href, "http://example.org/", + openedBrowser.loadURI(WEB_ADDRESS); + let href = await BrowserTestUtils.browserLoaded(openedBrowser, false, WEB_ADDRESS); + is(href, WEB_ADDRESS, "Check that new file:// page has navigated successfully to web content"); }); diff --git a/browser/themes/linux/browser.css b/browser/themes/linux/browser.css index 6503924b12cc..d2e79c709ff0 100644 --- a/browser/themes/linux/browser.css +++ b/browser/themes/linux/browser.css @@ -69,11 +69,11 @@ border-top: none; } -#navigator-toolbox > toolbar { +.browser-toolbar { padding: 0; } -#navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar) { +.browser-toolbar:not(.titlebar-color) { background-color: var(--toolbar-bgcolor); background-image: var(--toolbar-bgimage); color: var(--toolbar-color, inherit); diff --git a/browser/themes/osx/browser.css b/browser/themes/osx/browser.css index eaa2ecdf1d46..3735ff176abe 100644 --- a/browser/themes/osx/browser.css +++ b/browser/themes/osx/browser.css @@ -142,7 +142,7 @@ border-top: 1px solid rgba(0,0,0,0.65); } -#navigator-toolbox > toolbar:not(#TabsToolbar) { +.browser-toolbar:not(#TabsToolbar) { -moz-appearance: none; background: var(--toolbar-bgcolor); color: var(--toolbar-color, inherit); diff --git a/browser/themes/shared/browser.inc.css b/browser/themes/shared/browser.inc.css index 0bb5c039936f..c950564f6493 100644 --- a/browser/themes/shared/browser.inc.css +++ b/browser/themes/shared/browser.inc.css @@ -47,32 +47,32 @@ /* Bookmark toolbar */ -#navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):not(#nav-bar) { +#PersonalToolbar { overflow: -moz-hidden-unscrollable; max-height: 4em; padding: 0 6px 2px; } -:root[sessionrestored] #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):not(#nav-bar) { +:root[sessionrestored] #PersonalToolbar { transition: min-height 170ms ease-out, max-height 170ms ease-out, @themeTransition@; } -#navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):not(#nav-bar)[collapsed=true] { +#PersonalToolbar[collapsed=true] { min-height: 0.1px; max-height: 0; } -:root[sessionrestored] #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):not(#nav-bar)[collapsed=true] { +:root[sessionrestored] #PersonalToolbar[collapsed=true] { transition: min-height 170ms ease-out, max-height 170ms ease-out, visibility 170ms linear; } -#navigator-toolbox > toolbar[customizing]:not(#toolbar-menubar):not(#TabsToolbar):not(#nav-bar) { +#PersonalToolbar[customizing] { outline: 1px dashed; outline-offset: -3px; -moz-outline-radius: 2px; } -#navigator-toolbox > toolbar[customizing]:not(#toolbar-menubar):not(#TabsToolbar):not(#nav-bar):empty { +#PersonalToolbar[customizing]:empty { /* Avoid the toolbar having no height when there's no items in it */ min-height: 22px; } diff --git a/browser/themes/shared/compacttheme.inc.css b/browser/themes/shared/compacttheme.inc.css index e3b445bcc2bd..01beb9330103 100644 --- a/browser/themes/shared/compacttheme.inc.css +++ b/browser/themes/shared/compacttheme.inc.css @@ -63,7 +63,7 @@ toolbar[brighttext] .toolbarbutton-1 { color: var(--chrome-color); } -#navigator-toolbox > toolbar:not(#TabsToolbar):not(#toolbar-menubar), +.browser-toolbar:not(.titlebar-color), .browserContainer > findbar, #browser-bottombox { background-color: var(--chrome-secondary-background-color) !important; diff --git a/browser/themes/windows/browser-aero.css b/browser/themes/windows/browser-aero.css index 37e6e3a499c6..fe37c1aecfb2 100644 --- a/browser/themes/windows/browser-aero.css +++ b/browser/themes/windows/browser-aero.css @@ -275,8 +275,8 @@ @media (-moz-os-version: windows-win7), (-moz-os-version: windows-win8) { /* Vertical toolbar border */ - #main-window[sizemode=normal] #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):not(:-moz-lwtheme), - #main-window[sizemode=normal] #navigator-toolbox > toolbar:-moz-lwtheme { + #main-window[sizemode=normal] .browser-toolbar:not(.titlebar-color):not(:-moz-lwtheme), + #main-window[sizemode=normal] .browser-toolbar:-moz-lwtheme { border-left: 1px solid @glassShadowColor@; border-right: 1px solid @glassShadowColor@; background-clip: padding-box; diff --git a/browser/themes/windows/browser.css b/browser/themes/windows/browser.css index 8806fffab322..02d3a328c6b3 100644 --- a/browser/themes/windows/browser.css +++ b/browser/themes/windows/browser.css @@ -131,11 +131,11 @@ } #navigator-toolbox, -#navigator-toolbox > toolbar { +.browser-toolbar { -moz-appearance: none; } -#navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar) { +.browser-toolbar:not(.titlebar-color) { background-color: var(--toolbar-bgcolor); background-image: var(--toolbar-bgimage); background-clip: padding-box; diff --git a/build/moz.configure/windows.configure b/build/moz.configure/windows.configure index 1e498ddbf2c1..517c68e3fa5d 100644 --- a/build/moz.configure/windows.configure +++ b/build/moz.configure/windows.configure @@ -462,6 +462,9 @@ set_config('MSMANIFEST_TOOL', depends(valid_mt)(lambda x: bool(x))) link = check_prog('LINKER', ('lld-link.exe', 'link.exe'), paths=toolchain_search_path) +host_link = check_prog('HOST_LINKER', ('lld-link.exe', 'link.exe'), + paths=toolchain_search_path) + add_old_configure_assignment('LINKER', link) diff --git a/config/rules.mk b/config/rules.mk index b8771f743027..2a23c475b099 100644 --- a/config/rules.mk +++ b/config/rules.mk @@ -592,7 +592,7 @@ endif $(HOST_PROGRAM): $(HOST_PROGOBJS) $(HOST_LIBS) $(HOST_EXTRA_DEPS) $(GLOBAL_DEPS) $(call mkdir_deps,$(DEPTH)/dist/host/bin) $(REPORT_BUILD) ifeq (_WINNT,$(GNU_CC)_$(HOST_OS_ARCH)) - $(LINKER) -NOLOGO -OUT:$@ -PDB:$(HOST_PDBFILE) $(HOST_OBJS) $(WIN32_EXE_LDFLAGS) $(HOST_LDFLAGS) $(HOST_LIBS) $(HOST_EXTRA_LIBS) + $(HOST_LINKER) -NOLOGO -OUT:$@ -PDB:$(HOST_PDBFILE) $(HOST_OBJS) $(WIN32_EXE_LDFLAGS) $(HOST_LDFLAGS) $(HOST_LIBS) $(HOST_EXTRA_LIBS) ifdef MSMANIFEST_TOOL @if test -f $@.manifest; then \ if test -f '$(srcdir)/$(notdir $@).manifest'; then \ @@ -653,7 +653,7 @@ endif $(HOST_SIMPLE_PROGRAMS): host_%$(HOST_BIN_SUFFIX): host_%.$(OBJ_SUFFIX) $(HOST_LIBS) $(HOST_EXTRA_DEPS) $(GLOBAL_DEPS) $(REPORT_BUILD) ifeq (WINNT_,$(HOST_OS_ARCH)_$(GNU_CC)) - $(LINKER) -NOLOGO -OUT:$@ -PDB:$(HOST_PDBFILE) $< $(WIN32_EXE_LDFLAGS) $(HOST_LIBS) $(HOST_EXTRA_LIBS) + $(HOST_LINKER) -NOLOGO -OUT:$@ -PDB:$(HOST_PDBFILE) $< $(WIN32_EXE_LDFLAGS) $(HOST_LDFLAGS) $(HOST_LIBS) $(HOST_EXTRA_LIBS) else ifneq (,$(HOST_CPPSRCS)$(USE_HOST_CXX)) $(HOST_CXX) $(HOST_OUTOPTION)$@ $(HOST_CXX_LDFLAGS) $< $(HOST_LIBS) $(HOST_EXTRA_LIBS) @@ -690,8 +690,7 @@ $(HOST_SHARED_LIBRARY): $(HOST_OBJS) Makefile $(REPORT_BUILD) $(RM) $@ ifdef _MSC_VER - # /!\ We assume host and target are using the same compiler - $(LINKER) -NOLOGO -DLL -OUT:$@ $(HOST_OBJS) $(HOST_CXX_LDFLAGS) $(HOST_LDFLAGS) $(HOST_LIBS) $(HOST_EXTRA_LIBS) + $(HOST_LINKER) -NOLOGO -DLL -OUT:$@ $(HOST_OBJS) $(HOST_CXX_LDFLAGS) $(HOST_LDFLAGS) $(HOST_LIBS) $(HOST_EXTRA_LIBS) else $(HOST_CXX) $(HOST_OUTOPTION)$@ $(HOST_OBJS) $(HOST_CXX_LDFLAGS) $(HOST_LDFLAGS) $(HOST_LIBS) $(HOST_EXTRA_LIBS) endif diff --git a/devtools/client/inspector/fonts/components/Font.js b/devtools/client/inspector/fonts/components/Font.js index bbd3383bae02..e931dee17357 100644 --- a/devtools/client/inspector/fonts/components/Font.js +++ b/devtools/client/inspector/fonts/components/Font.js @@ -18,8 +18,7 @@ class Font extends PureComponent { static get propTypes() { return { font: PropTypes.shape(Types.font).isRequired, - fontOptions: PropTypes.shape(Types.fontOptions).isRequired, - onPreviewFonts: PropTypes.func.isRequired, + onPreviewClick: PropTypes.func, onToggleFontHighlight: PropTypes.func.isRequired, }; } @@ -108,13 +107,10 @@ class Font extends PureComponent { render() { const { font, - fontOptions, - onPreviewFonts, + onPreviewClick, onToggleFontHighlight, } = this.props; - const { previewText } = fontOptions; - const { CSSFamilyName, previewUrl, @@ -132,7 +128,7 @@ class Font extends PureComponent { FontName({ font, onToggleFontHighlight }) ), FontOrigin({ font }), - FontPreview({ previewText, previewUrl, onPreviewFonts }), + FontPreview({ onPreviewClick, previewUrl }), this.renderFontCSSCode(rule, ruleText) ); } diff --git a/devtools/client/inspector/fonts/components/FontList.js b/devtools/client/inspector/fonts/components/FontList.js index dab19c515106..3bf56abfcd39 100644 --- a/devtools/client/inspector/fonts/components/FontList.js +++ b/devtools/client/inspector/fonts/components/FontList.js @@ -4,44 +4,83 @@ "use strict"; -const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react"); +const Services = require("Services"); +const { + createElement, + createFactory, + createRef, + Fragment, + PureComponent, +} = require("devtools/client/shared/vendor/react"); const dom = require("devtools/client/shared/vendor/react-dom-factories"); const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); const Font = createFactory(require("./Font")); +const FontPreviewInput = createFactory(require("./FontPreviewInput")); const Types = require("../types"); +const PREF_FONT_EDITOR = "devtools.inspector.fonteditor.enabled"; + class FontList extends PureComponent { static get propTypes() { return { fontOptions: PropTypes.shape(Types.fontOptions).isRequired, fonts: PropTypes.arrayOf(PropTypes.shape(Types.font)).isRequired, - onPreviewFonts: PropTypes.func.isRequired, + onPreviewTextChange: PropTypes.func.isRequired, onToggleFontHighlight: PropTypes.func.isRequired, }; } + constructor(props) { + super(props); + + this.onPreviewClick = this.onPreviewClick.bind(this); + this.previewInputRef = createRef(); + } + + /** + * Handler for clicks on the font preview image. + * Requests the FontPreviewInput component, if one exists, to focus its input field. + */ + onPreviewClick() { + this.previewInputRef.current && this.previewInputRef.current.focus(); + } + render() { const { fonts, fontOptions, - onPreviewFonts, + onPreviewTextChange, onToggleFontHighlight } = this.props; - return dom.ul( + const { previewText } = fontOptions; + const { onPreviewClick } = this; + + const list = dom.ul( { className: "fonts-list" }, fonts.map((font, i) => Font({ key: i, font, - fontOptions, - onPreviewFonts, + onPreviewClick, onToggleFontHighlight, })) ); + + // Show the font preview input only when the font editor is enabled. + const previewInput = Services.prefs.getBoolPref(PREF_FONT_EDITOR) ? + FontPreviewInput({ + ref: this.previewInputRef, + onPreviewTextChange, + previewText, + }) + : + null; + + return createElement(Fragment, null, previewInput, list); } } diff --git a/devtools/client/inspector/fonts/components/FontOverview.js b/devtools/client/inspector/fonts/components/FontOverview.js index 53f1fb52c2e0..1c8927d6ceee 100644 --- a/devtools/client/inspector/fonts/components/FontOverview.js +++ b/devtools/client/inspector/fonts/components/FontOverview.js @@ -22,7 +22,7 @@ class FontOverview extends PureComponent { return { fontData: PropTypes.shape(Types.fontData).isRequired, fontOptions: PropTypes.shape(Types.fontOptions).isRequired, - onPreviewFonts: PropTypes.func.isRequired, + onPreviewTextChange: PropTypes.func.isRequired, onToggleFontHighlight: PropTypes.func.isRequired, }; } @@ -38,7 +38,7 @@ class FontOverview extends PureComponent { const { fontData, fontOptions, - onPreviewFonts, + onPreviewTextChange, onToggleFontHighlight, } = this.props; const { fonts } = fontData; @@ -47,7 +47,7 @@ class FontOverview extends PureComponent { FontList({ fonts, fontOptions, - onPreviewFonts, + onPreviewTextChange, onToggleFontHighlight, }) : @@ -63,7 +63,7 @@ class FontOverview extends PureComponent { const { fontData, fontOptions, - onPreviewFonts, + onPreviewTextChange, } = this.props; const header = Services.prefs.getBoolPref(PREF_FONT_EDITOR) @@ -86,7 +86,7 @@ class FontOverview extends PureComponent { componentProps: { fontOptions, fonts, - onPreviewFonts, + onPreviewTextChange, onToggleFontHighlight: this.onToggleFontHighlightGlobal }, opened: false diff --git a/devtools/client/inspector/fonts/components/FontPreview.js b/devtools/client/inspector/fonts/components/FontPreview.js index af7b29339f59..581d9b71e4a8 100644 --- a/devtools/client/inspector/fonts/components/FontPreview.js +++ b/devtools/client/inspector/fonts/components/FontPreview.js @@ -9,86 +9,33 @@ const dom = require("devtools/client/shared/vendor/react-dom-factories"); const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); const Types = require("../types"); -const { getStr } = require("../utils/l10n"); class FontPreview extends PureComponent { static get propTypes() { return { - previewText: Types.fontOptions.previewText.isRequired, + onPreviewClick: PropTypes.func, previewUrl: Types.font.previewUrl.isRequired, - onPreviewFonts: PropTypes.func.isRequired, }; } - constructor(props) { - super(props); - - this.state = { - // Is the text preview input field currently focused? - isFocused: false, + static get defaultProps() { + return { + onPreviewClick: () => {}, }; - - this.onBlur = this.onBlur.bind(this); - this.onClick = this.onClick.bind(this); - this.onChange = this.onChange.bind(this); - } - - componentDidUpdate() { - if (this.state.isFocused) { - const input = this.fontPreviewInput; - input.focus(); - input.selectionStart = input.selectionEnd = input.value.length; - } - } - - onBlur() { - this.setState({ isFocused: false }); - } - - onClick(event) { - this.setState({ isFocused: true }); - event.stopPropagation(); - } - - onChange(event) { - this.props.onPreviewFonts(event.target.value); } render() { const { - previewText, + onPreviewClick, previewUrl, } = this.props; - const { isFocused } = this.state; - - return dom.div( + return dom.img( { - className: "font-preview-container", - }, - isFocused ? - dom.input( - { - type: "search", - className: "font-preview-input devtools-searchinput", - value: previewText, - onBlur: this.onBlur, - onChange: this.onChange, - ref: input => { - this.fontPreviewInput = input; - } - } - ) - : - null, - dom.img( - { - className: "font-preview", - src: previewUrl, - onClick: this.onClick, - title: !isFocused ? getStr("fontinspector.editPreview") : "", - } - ) + className: "font-preview", + onClick: onPreviewClick, + src: previewUrl, + } ); } } diff --git a/devtools/client/inspector/fonts/components/FontPreviewInput.js b/devtools/client/inspector/fonts/components/FontPreviewInput.js new file mode 100644 index 000000000000..3e9fe400e1df --- /dev/null +++ b/devtools/client/inspector/fonts/components/FontPreviewInput.js @@ -0,0 +1,72 @@ +/* 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 { createRef, PureComponent } = require("devtools/client/shared/vendor/react"); +const dom = require("devtools/client/shared/vendor/react-dom-factories"); +const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); + +const Types = require("../types"); +const { getStr } = require("../utils/l10n"); + +const PREVIEW_TEXT_MAX_LENGTH = 30; + +class FontPreviewInput extends PureComponent { + static get propTypes() { + return { + onPreviewTextChange: PropTypes.func.isRequired, + previewText: Types.fontOptions.previewText.isRequired, + }; + } + + constructor(props) { + super(props); + + this.onChange = this.onChange.bind(this); + this.onFocus = this.onFocus.bind(this); + this.inputRef = createRef(); + + this.state = { + value: this.props.previewText + }; + } + + onChange(e) { + const value = e.target.value; + this.props.onPreviewTextChange(value); + + this.setState((prevState) => { + return { ...prevState, value }; + }); + } + + onFocus(e) { + e.target.select(); + } + + focus() { + this.inputRef.current.focus(); + } + + render() { + return dom.div( + { + id: "font-preview-input-container", + }, + dom.input({ + className: "devtools-searchinput", + onChange: this.onChange, + onFocus: this.onFocus, + maxlength: PREVIEW_TEXT_MAX_LENGTH, + placeholder: getStr("fontinspector.previewTextPlaceholder"), + ref: this.inputRef, + type: "text", + value: this.state.value, + }) + ); + } +} + +module.exports = FontPreviewInput; diff --git a/devtools/client/inspector/fonts/components/FontsApp.js b/devtools/client/inspector/fonts/components/FontsApp.js index c14d66a2c6ef..4a22ff0ca6a2 100644 --- a/devtools/client/inspector/fonts/components/FontsApp.js +++ b/devtools/client/inspector/fonts/components/FontsApp.js @@ -22,7 +22,7 @@ class FontsApp extends PureComponent { fontEditorEnabled: PropTypes.bool.isRequired, fontOptions: PropTypes.shape(Types.fontOptions).isRequired, onInstanceChange: PropTypes.func.isRequired, - onPreviewFonts: PropTypes.func.isRequired, + onPreviewTextChange: PropTypes.func.isRequired, onPropertyChange: PropTypes.func.isRequired, onToggleFontHighlight: PropTypes.func.isRequired, }; @@ -35,7 +35,7 @@ class FontsApp extends PureComponent { fontEditorEnabled, fontOptions, onInstanceChange, - onPreviewFonts, + onPreviewTextChange, onPropertyChange, onToggleFontHighlight, } = this.props; @@ -54,7 +54,7 @@ class FontsApp extends PureComponent { FontOverview({ fontData, fontOptions, - onPreviewFonts, + onPreviewTextChange, onToggleFontHighlight, }) ); diff --git a/devtools/client/inspector/fonts/components/moz.build b/devtools/client/inspector/fonts/components/moz.build index e0ea79eff469..bd0013bcf2d6 100644 --- a/devtools/client/inspector/fonts/components/moz.build +++ b/devtools/client/inspector/fonts/components/moz.build @@ -12,6 +12,7 @@ DevToolsModules( 'FontOrigin.js', 'FontOverview.js', 'FontPreview.js', + 'FontPreviewInput.js', 'FontPropertyValue.js', 'FontsApp.js', 'FontSize.js', diff --git a/devtools/client/inspector/fonts/fonts.js b/devtools/client/inspector/fonts/fonts.js index 3eda5710e982..73fbaa966183 100644 --- a/devtools/client/inspector/fonts/fonts.js +++ b/devtools/client/inspector/fonts/fonts.js @@ -83,7 +83,7 @@ class FontInspector { this.syncChanges = debounce(this.syncChanges, 100, this); this.onInstanceChange = this.onInstanceChange.bind(this); this.onNewNode = this.onNewNode.bind(this); - this.onPreviewFonts = this.onPreviewFonts.bind(this); + this.onPreviewTextChange = debounce(this.onPreviewTextChange, 100, this); this.onPropertyChange = this.onPropertyChange.bind(this); this.onRulePropertyUpdated = debounce(this.onRulePropertyUpdated, 100, this); this.onToggleFontHighlight = this.onToggleFontHighlight.bind(this); @@ -103,7 +103,7 @@ class FontInspector { fontEditorEnabled: Services.prefs.getBoolPref(PREF_FONT_EDITOR), onInstanceChange: this.onInstanceChange, onToggleFontHighlight: this.onToggleFontHighlight, - onPreviewFonts: this.onPreviewFonts, + onPreviewTextChange: this.onPreviewTextChange, onPropertyChange: this.onPropertyChange, }); @@ -683,7 +683,7 @@ class FontInspector { /** * Handler for change in preview input. */ - onPreviewFonts(value) { + onPreviewTextChange(value) { this.store.dispatch(updatePreviewText(value)); this.update(); } diff --git a/devtools/client/inspector/fonts/reducers/font-options.js b/devtools/client/inspector/fonts/reducers/font-options.js index 857cf981a69b..44ce612b5034 100644 --- a/devtools/client/inspector/fonts/reducers/font-options.js +++ b/devtools/client/inspector/fonts/reducers/font-options.js @@ -9,7 +9,7 @@ const { } = require("../actions/index"); const INITIAL_FONT_OPTIONS = { - previewText: "Abc", + previewText: "", }; const reducers = { diff --git a/devtools/client/inspector/fonts/test/head.js b/devtools/client/inspector/fonts/test/head.js index 1886d148cbce..de7ffa4278d6 100644 --- a/devtools/client/inspector/fonts/test/head.js +++ b/devtools/client/inspector/fonts/test/head.js @@ -61,7 +61,7 @@ var openFontInspectorForURL = async function(url) { }; /** - * Focus one of the preview inputs, clear it, type new text into it and wait for the + * Focus the preview input, clear it, type new text into it and wait for the * preview images to be updated. * * @param {FontInspector} view - The FontInspector instance. @@ -71,15 +71,8 @@ async function updatePreviewText(view, text) { info(`Changing the preview text to '${text}'`); const doc = view.document; - const previewImg = doc.querySelector("#sidebar-panel-fontinspector .font-preview"); - - info("Clicking the font preview element to turn it to edit mode"); - const onClick = once(doc, "click"); - previewImg.click(); - await onClick; - - const input = previewImg.parentNode.querySelector("input"); - is(doc.activeElement, input, "The input was focused."); + const input = doc.querySelector("#font-preview-input-container input"); + input.focus(); info("Blanking the input field."); while (input.value.length) { @@ -89,13 +82,13 @@ async function updatePreviewText(view, text) { } if (text) { - info("Typing the specified text to the input field."); - const update = waitForNEvents(view.inspector, "fontinspector-updated", text.length); + info(`Typing "${text}" into the input field.`); + const update = view.inspector.once("fontinspector-updated"); EventUtils.sendString(text, doc.defaultView); await update; } - is(input.value, text, "The input now contains the correct text."); + is(input.value, text, `The input now contains "${text}".`); } /** diff --git a/devtools/client/locales/en-US/font-inspector.properties b/devtools/client/locales/en-US/font-inspector.properties index f5163f749dad..5e25253f640f 100644 --- a/devtools/client/locales/en-US/font-inspector.properties +++ b/devtools/client/locales/en-US/font-inspector.properties @@ -17,11 +17,6 @@ fontinspector.noFontsOnSelectedElement=No fonts were found for the current eleme # header of a collapsible section containing other fonts used in the page. fontinspector.otherFontsInPageHeader=Other fonts in page -# LOCALIZATION NOTE (fontinspector.editPreview): This is the text that appears in a -# tooltip on hover of a font preview string. Clicking on the string opens a text input -# where users can type to change the preview text. -fontinspector.editPreview=Click to edit preview - # LOCALIZATION NOTE (fontinspector.copyURL): This is the text that appears in a tooltip # displayed when the user hovers over the copy icon next to the font URL. # Clicking the copy icon copies the full font URL to the user's clipboard @@ -72,3 +67,7 @@ fontinspector.allFontsOnPageHeader=All fonts on page # LOCALIZATION NOTE (fontinspector.usedFontsLabel): Label for the Font Editor section # which shows the fonts used on the selected element. fontinspector.usedFontsLabel=Fonts used + +# LOCALIZATION NOTE (fontinspector.previewTextPlaceholder): Placeholder for the input +# where the user can type text to get a preview of it using a font. +fontinspector.previewTextPlaceholder=Font preview text diff --git a/devtools/client/themes/fonts.css b/devtools/client/themes/fonts.css index b5e68e56857e..b4de8c079c37 100644 --- a/devtools/client/themes/fonts.css +++ b/devtools/client/themes/fonts.css @@ -9,6 +9,7 @@ --input-background-color: white; --input-border-color: var(--grey-30); --input-text-color: var(--grey-90); + --preview-input-background: var(--theme-toolbar-background); } :root.theme-dark { @@ -17,6 +18,7 @@ --input-background-color: var(--grey-70); --input-border-color: var(--grey-70); --input-text-color: var(--grey-40); + --preview-input-background: #222225; } #sidebar-panel-fontinspector { @@ -82,44 +84,25 @@ vertical-align: bottom; } -.font-preview-container { - grid-column: 2; - grid-row: 1 / span 2; - overflow: hidden; - display: grid; - place-items: center end; - position: relative; +#font-preview-input-container { + background: var(--preview-input-background); + border-bottom: 1px solid var(--theme-splitter-color); + display: flex; + height: 23px; +} + +#font-preview-input-container input { + background-image: none; + flex: 1; + padding-left: 14px; } .font-preview { + grid-column: 2; + grid-row: 1 / span 2; + object-fit: contain; height: 50px; - display: block; -} - -.font-preview:hover { - cursor: text; - background-image: linear-gradient(to right, - var(--grey-40) 3px, transparent 3px, transparent); - background-size: 6px 1px; - background-repeat: repeat-x; - background-position-y: 45px; -} - -#font-container .font-preview-input { - position: absolute; - top: 5px; - left: 0; - width: calc(100% - 5px); - height: calc(100% - 10px); - background: transparent; - color: transparent; - border-radius: 0; - padding: 0; -} - -.font-preview-input::-moz-selection { - background: transparent; - color: transparent; + width: 100%; } .font-name, diff --git a/devtools/client/themes/images/command-responsivemode.svg b/devtools/client/themes/images/command-responsivemode.svg index c6f454c256ae..df207e1b2527 100644 --- a/devtools/client/themes/images/command-responsivemode.svg +++ b/devtools/client/themes/images/command-responsivemode.svg @@ -1,12 +1,4 @@ - - - - - + + + diff --git a/devtools/client/themes/toolbox.css b/devtools/client/themes/toolbox.css index 144d93265743..059d1874000b 100644 --- a/devtools/client/themes/toolbox.css +++ b/devtools/client/themes/toolbox.css @@ -283,6 +283,8 @@ #command-button-responsive::before { background-image: var(--command-responsive-image); + fill: var(--theme-toolbar-photon-icon-color); + -moz-context-properties: fill; } #command-button-scratchpad::before { diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp index 85c807d204d3..587a32d351ce 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -542,8 +542,13 @@ Navigator::CookieEnabled() return cookieEnabled; } - return AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(mWindow, - codebaseURI); + if (AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(mWindow, + codebaseURI)) { + return true; + } + + AntiTrackingCommon::NotifyRejection(mWindow); + return false; } bool diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index e64a56336184..06905eade2fb 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -8917,28 +8917,10 @@ nsContentUtils::StorageDisabledByAntiTracking(nsPIDOMWindowInner* aWindow, bool disabled = StorageDisabledByAntiTrackingInternal(aWindow, aChannel, aPrincipal, aURI); if (disabled && sAntiTrackingControlCenterUIEnabled) { - nsCOMPtr thirdPartyUtil = services::GetThirdPartyUtil(); - if (!thirdPartyUtil) { - return false; - } - - nsCOMPtr pwin; if (aWindow) { - auto* outer = nsGlobalWindowOuter::Cast(aWindow->GetOuterWindow()); - if (outer) { - pwin = outer->GetTopOuter(); - } + AntiTrackingCommon::NotifyRejection(aWindow); } else if (aChannel) { - nsCOMPtr win; - nsresult rv = thirdPartyUtil->GetTopWindowForChannel(aChannel, - getter_AddRefs(win)); - NS_ENSURE_SUCCESS(rv, false); - pwin = nsPIDOMWindowOuter::From(win); - } - - if (pwin && aChannel) { - pwin->NotifyContentBlockingState( - nsIWebProgressListener::STATE_BLOCKED_TRACKING_COOKIES, aChannel); + AntiTrackingCommon::NotifyRejection(aChannel); } } return disabled; diff --git a/extensions/pref/autoconfig/src/nsReadConfig.cpp b/extensions/pref/autoconfig/src/nsReadConfig.cpp index 11ff75df0137..dbf992ed1074 100644 --- a/extensions/pref/autoconfig/src/nsReadConfig.cpp +++ b/extensions/pref/autoconfig/src/nsReadConfig.cpp @@ -101,7 +101,7 @@ NS_IMETHODIMP nsReadConfig::Observe(nsISupports *aSubject, const char *aTopic, c if (NS_FAILED(rv)) { if (sandboxEnabled) { nsContentUtils::ReportToConsoleNonLocalized( - NS_LITERAL_STRING("Autoconfig is sandboxed by default. See https://www.mozilla.org/firefox/enterprise/releasenotes/ for more information."), + NS_LITERAL_STRING("Autoconfig is sandboxed by default. See https://support.mozilla.org/products/firefox-enterprise for more information."), nsIScriptError::warningFlag, NS_LITERAL_CSTRING("autoconfig"), nullptr); diff --git a/gfx/webrender/res/brush_blend.glsl b/gfx/webrender/res/brush_blend.glsl index 5445e7d70d3a..9f925a067b88 100644 --- a/gfx/webrender/res/brush_blend.glsl +++ b/gfx/webrender/res/brush_blend.glsl @@ -32,7 +32,10 @@ void brush_vs( vec2 uv = snap_device_pos(vi) + src_task.common_data.task_rect.p0 - src_task.content_origin; - vUv = vec3(uv / texture_size, src_task.common_data.texture_layer_index); + vUv = vec3( + uv * gl_Position.w / texture_size, // multiply by W to compensate for perspective interpolation + src_task.common_data.texture_layer_index + ); vec2 uv0 = src_task.common_data.task_rect.p0; vec2 uv1 = uv0 + src_task.common_data.task_rect.size; @@ -124,7 +127,8 @@ vec3 Brightness(vec3 Cs, float amount) { } Fragment brush_fs() { - vec4 Cs = texture(sColor0, vUv); + vec2 base_uv = vUv.xy * gl_FragCoord.w; + vec4 Cs = texture(sColor0, vec3(base_uv, vUv.z)); if (Cs.a == 0.0) { return Fragment(vec4(0.0)); // could also `discard` @@ -155,7 +159,7 @@ Fragment brush_fs() { // Fail-safe to ensure that we don't sample outside the rendered // portion of a blend source. - alpha *= point_inside_rect(vUv.xy, vUvClipBounds.xy, vUvClipBounds.zw); + alpha *= point_inside_rect(base_uv, vUvClipBounds.xy, vUvClipBounds.zw); // Pre-multiply the alpha into the output value. return Fragment(alpha * vec4(color, 1.0)); diff --git a/gfx/webrender/src/batch.rs b/gfx/webrender/src/batch.rs index 3986f94121b4..e0bf8881fcc3 100644 --- a/gfx/webrender/src/batch.rs +++ b/gfx/webrender/src/batch.rs @@ -829,6 +829,7 @@ impl AlphaBatchBuilder { ); let filter_mode = match filter { + FilterOp::Identity => 1, // matches `Contrast(1)` FilterOp::Blur(..) => 0, FilterOp::Contrast(..) => 1, FilterOp::Grayscale(..) => 2, @@ -843,6 +844,7 @@ impl AlphaBatchBuilder { }; let user_data = match filter { + FilterOp::Identity => 0x10000i32, // matches `Contrast(1)` FilterOp::Contrast(amount) | FilterOp::Grayscale(amount) | FilterOp::Invert(amount) | diff --git a/gfx/webrender/src/clip.rs b/gfx/webrender/src/clip.rs index fb4a57e69e4b..631d66297952 100644 --- a/gfx/webrender/src/clip.rs +++ b/gfx/webrender/src/clip.rs @@ -324,6 +324,7 @@ pub struct ClipChainInstance { pub clips_range: ClipNodeRange, pub local_clip_rect: LayoutRect, pub has_non_root_coord_system: bool, + pub has_non_local_clips: bool, pub world_clip_rect: WorldRect, } @@ -531,6 +532,7 @@ impl ClipStore { let first_clip_node_index = self.clip_node_indices.len() as u32; let mut has_non_root_coord_system = false; + let mut has_non_local_clips = false; // For each potential clip node for node_info in self.clip_node_info.drain(..) { @@ -542,9 +544,11 @@ impl ClipStore { node.item.get_clip_result(&local_bounding_rect) } ClipSpaceConversion::Offset(offset) => { + has_non_local_clips = true; node.item.get_clip_result(&local_bounding_rect.translate(&-offset)) } ClipSpaceConversion::Transform(ref transform) => { + has_non_local_clips = true; node.item.get_clip_result_complex( transform, &world_bounding_rect, @@ -603,6 +607,7 @@ impl ClipStore { Some(ClipChainInstance { clips_range, has_non_root_coord_system, + has_non_local_clips, local_clip_rect, world_clip_rect, }) diff --git a/gfx/webrender/src/prim_store.rs b/gfx/webrender/src/prim_store.rs index eac7b27de457..8c4c33b1eaac 100644 --- a/gfx/webrender/src/prim_store.rs +++ b/gfx/webrender/src/prim_store.rs @@ -2211,7 +2211,8 @@ impl Primitive { match segment_clip_chain { Some(segment_clip_chain) => { - if segment_clip_chain.clips_range.count == 0 { + if segment_clip_chain.clips_range.count == 0 || + (!segment.may_need_clip_mask && !segment_clip_chain.has_non_local_clips) { segment.clip_task_id = BrushSegmentTaskId::Opaque; continue; } diff --git a/gfx/webrender/src/scene.rs b/gfx/webrender/src/scene.rs index ef55211cabbf..ce0891917d42 100644 --- a/gfx/webrender/src/scene.rs +++ b/gfx/webrender/src/scene.rs @@ -201,6 +201,7 @@ pub trait FilterOpHelpers { impl FilterOpHelpers for FilterOp { fn is_visible(&self) -> bool { match *self { + FilterOp::Identity | FilterOp::Blur(..) | FilterOp::Brightness(..) | FilterOp::Contrast(..) | @@ -219,6 +220,7 @@ impl FilterOpHelpers for FilterOp { fn is_noop(&self) -> bool { match *self { + FilterOp::Identity => false, // this is intentional FilterOp::Blur(length) => length == 0.0, FilterOp::Brightness(amount) => amount == 1.0, FilterOp::Contrast(amount) => amount == 1.0, diff --git a/gfx/webrender_api/src/display_item.rs b/gfx/webrender_api/src/display_item.rs index 040e6f64eeea..29fe0fd69bcb 100644 --- a/gfx/webrender_api/src/display_item.rs +++ b/gfx/webrender_api/src/display_item.rs @@ -543,6 +543,9 @@ pub enum MixBlendMode { #[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize)] pub enum FilterOp { + /// Filter that does no transformation of the colors, needed for + /// debug purposes only. + Identity, Blur(f32), Brightness(f32), Contrast(f32), diff --git a/gfx/webrender_api/src/display_list.rs b/gfx/webrender_api/src/display_list.rs index 32cc718324c2..9b5b35c857ad 100644 --- a/gfx/webrender_api/src/display_list.rs +++ b/gfx/webrender_api/src/display_list.rs @@ -16,7 +16,7 @@ use time::precise_time_ns; use {AlphaType, BorderDetails, BorderDisplayItem, BorderRadius, BorderWidths, BoxShadowClipMode}; use {BoxShadowDisplayItem, ClipAndScrollInfo, ClipChainId, ClipChainItem, ClipDisplayItem, ClipId}; use {ColorF, ComplexClipRegion, DisplayItem, ExtendMode, ExternalScrollId, FilterOp}; -use {FontInstanceKey, GlyphInstance, GlyphOptions, GlyphRasterSpace, Gradient}; +use {FontInstanceKey, GlyphInstance, GlyphOptions, GlyphRasterSpace, Gradient, GradientBuilder}; use {GradientDisplayItem, GradientStop, IframeDisplayItem, ImageDisplayItem, ImageKey, ImageMask}; use {ImageRendering, LayoutPoint, LayoutPrimitiveInfo, LayoutRect, LayoutSize, LayoutTransform}; use {LayoutVector2D, LineDisplayItem, LineOrientation, LineStyle, MixBlendMode, PipelineId}; @@ -947,7 +947,12 @@ impl DisplayListBuilder { index } - fn push_item(&mut self, item: SpecificDisplayItem, info: &LayoutPrimitiveInfo) { + /// Add an item to the display list. + /// + /// NOTE: It is usually preferable to use the specialized methods to push + /// display items. Pushing unexpected or invalid items here may + /// result in WebRender panicking or behaving in unexpected ways. + pub fn push_item(&mut self, item: SpecificDisplayItem, info: &LayoutPrimitiveInfo) { serialize_fast( &mut self.data, &DisplayItem { @@ -1018,7 +1023,11 @@ impl DisplayListBuilder { debug_assert_eq!(len, count); } - fn push_iter(&mut self, iter: I) + /// Push items from an iterator to the display list. + /// + /// NOTE: Pushing unexpected or invalid items to the display list + /// may result in panic and confusion. + pub fn push_iter(&mut self, iter: I) where I: IntoIterator, I::IntoIter: ExactSizeIterator + Clone, @@ -1112,129 +1121,34 @@ impl DisplayListBuilder { } } - // Gradients can be defined with stops outside the range of [0, 1] - // when this happens the gradient needs to be normalized by adjusting - // the gradient stops and gradient line into an equivalent gradient - // with stops in the range [0, 1]. this is done by moving the beginning - // of the gradient line to where stop[0] and the end of the gradient line - // to stop[n-1]. this function adjusts the stops in place, and returns - // the amount to adjust the gradient line start and stop - fn normalize_stops(stops: &mut Vec, extend_mode: ExtendMode) -> (f32, f32) { - assert!(stops.len() >= 2); - - let first = *stops.first().unwrap(); - let last = *stops.last().unwrap(); - - assert!(first.offset <= last.offset); - - let stops_delta = last.offset - first.offset; - - if stops_delta > 0.000001 { - for stop in stops { - stop.offset = (stop.offset - first.offset) / stops_delta; - } - - (first.offset, last.offset) - } else { - // We have a degenerate gradient and can't accurately transform the stops - // what happens here depends on the repeat behavior, but in any case - // we reconstruct the gradient stops to something simpler and equivalent - stops.clear(); - - match extend_mode { - ExtendMode::Clamp => { - // This gradient is two colors split at the offset of the stops, - // so create a gradient with two colors split at 0.5 and adjust - // the gradient line so 0.5 is at the offset of the stops - stops.push(GradientStop { color: first.color, offset: 0.0, }); - stops.push(GradientStop { color: first.color, offset: 0.5, }); - stops.push(GradientStop { color: last.color, offset: 0.5, }); - stops.push(GradientStop { color: last.color, offset: 1.0, }); - - let offset = last.offset; - - (offset - 0.5, offset + 0.5) - } - ExtendMode::Repeat => { - // A repeating gradient with stops that are all in the same - // position should just display the last color. I believe the - // spec says that it should be the average color of the gradient, - // but this matches what Gecko and Blink does - stops.push(GradientStop { color: last.color, offset: 0.0, }); - stops.push(GradientStop { color: last.color, offset: 1.0, }); - - (0.0, 1.0) - } - } - } - } - - // NOTE: gradients must be pushed in the order they're created - // because create_gradient stores the stops in anticipation + /// NOTE: gradients must be pushed in the order they're created + /// because create_gradient stores the stops in anticipation. pub fn create_gradient( &mut self, start_point: LayoutPoint, end_point: LayoutPoint, - mut stops: Vec, + stops: Vec, extend_mode: ExtendMode, ) -> Gradient { - let (start_offset, end_offset) = - DisplayListBuilder::normalize_stops(&mut stops, extend_mode); - - let start_to_end = end_point - start_point; - - self.push_stops(&stops); - - Gradient { - start_point: start_point + start_to_end * start_offset, - end_point: start_point + start_to_end * end_offset, - extend_mode, - } + let mut builder = GradientBuilder::with_stops(stops); + let gradient = builder.gradient(start_point, end_point, extend_mode); + self.push_stops(builder.stops()); + gradient } - // NOTE: gradients must be pushed in the order they're created - // because create_gradient stores the stops in anticipation + /// NOTE: gradients must be pushed in the order they're created + /// because create_gradient stores the stops in anticipation. pub fn create_radial_gradient( &mut self, center: LayoutPoint, radius: LayoutSize, - mut stops: Vec, + stops: Vec, extend_mode: ExtendMode, ) -> RadialGradient { - if radius.width <= 0.0 || radius.height <= 0.0 { - // The shader cannot handle a non positive radius. So - // reuse the stops vector and construct an equivalent - // gradient. - let last_color = stops.last().unwrap().color; - - let stops = [ - GradientStop { offset: 0.0, color: last_color, }, - GradientStop { offset: 1.0, color: last_color, }, - ]; - - self.push_stops(&stops); - - return RadialGradient { - center, - radius: LayoutSize::new(1.0, 1.0), - start_offset: 0.0, - end_offset: 1.0, - extend_mode, - }; - } - - let (start_offset, end_offset) = - DisplayListBuilder::normalize_stops(&mut stops, extend_mode); - - self.push_stops(&stops); - - RadialGradient { - center, - radius, - start_offset, - end_offset, - extend_mode, - } + let mut builder = GradientBuilder::with_stops(stops); + let gradient = builder.radial_gradient(center, radius, extend_mode); + self.push_stops(builder.stops()); + gradient } pub fn push_border( diff --git a/gfx/webrender_api/src/gradient_builder.rs b/gfx/webrender_api/src/gradient_builder.rs new file mode 100644 index 000000000000..ecf2605ffea7 --- /dev/null +++ b/gfx/webrender_api/src/gradient_builder.rs @@ -0,0 +1,153 @@ +/* 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 {ExtendMode, Gradient, GradientStop, LayoutPoint, LayoutSize, RadialGradient}; + + +/// Construct a gradient to be used in display lists. +/// +/// Each gradient needs at least two stops. +pub struct GradientBuilder { + stops: Vec, +} + +impl GradientBuilder { + /// Create a new gradient builder. + pub fn new() -> GradientBuilder { + GradientBuilder { + stops: Vec::new(), + } + } + + /// Create a gradient builder with a list of stops. + pub fn with_stops(stops: Vec) -> GradientBuilder { + GradientBuilder { stops } + } + + /// Push an additional stop for the gradient. + pub fn push(&mut self, stop: GradientStop) { + self.stops.push(stop); + } + + /// Get a reference to the list of stops. + pub fn stops(&self) -> &[GradientStop] { + self.stops.as_ref() + } + + /// Produce a linear gradient, normalize the stops. + pub fn gradient( + &mut self, + start_point: LayoutPoint, + end_point: LayoutPoint, + extend_mode: ExtendMode, + ) -> Gradient { + let (start_offset, end_offset) = self.normalize(extend_mode); + let start_to_end = end_point - start_point; + + Gradient { + start_point: start_point + start_to_end * start_offset, + end_point: start_point + start_to_end * end_offset, + extend_mode, + } + } + + /// Produce a radial gradient, normalize the stops. + /// + /// Will replace the gradient with a single color + /// if the radius negative. + pub fn radial_gradient( + &mut self, + center: LayoutPoint, + radius: LayoutSize, + extend_mode: ExtendMode, + ) -> RadialGradient { + if radius.width <= 0.0 || radius.height <= 0.0 { + // The shader cannot handle a non positive radius. So + // reuse the stops vector and construct an equivalent + // gradient. + let last_color = self.stops.last().unwrap().color; + + self.stops.clear(); + self.stops.push(GradientStop { offset: 0.0, color: last_color, }); + self.stops.push(GradientStop { offset: 1.0, color: last_color, }); + + return RadialGradient { + center, + radius: LayoutSize::new(1.0, 1.0), + start_offset: 0.0, + end_offset: 1.0, + extend_mode, + }; + } + + let (start_offset, end_offset) = + self.normalize(extend_mode); + + RadialGradient { + center, + radius, + start_offset, + end_offset, + extend_mode, + } + } + + /// Gradients can be defined with stops outside the range of [0, 1] + /// when this happens the gradient needs to be normalized by adjusting + /// the gradient stops and gradient line into an equivalent gradient + /// with stops in the range [0, 1]. this is done by moving the beginning + /// of the gradient line to where stop[0] and the end of the gradient line + /// to stop[n-1]. this function adjusts the stops in place, and returns + /// the amount to adjust the gradient line start and stop. + fn normalize(&mut self, extend_mode: ExtendMode) -> (f32, f32) { + let stops = &mut self.stops; + assert!(stops.len() >= 2); + + let first = *stops.first().unwrap(); + let last = *stops.last().unwrap(); + + assert!(first.offset <= last.offset); + + let stops_delta = last.offset - first.offset; + + if stops_delta > 0.000001 { + for stop in stops { + stop.offset = (stop.offset - first.offset) / stops_delta; + } + + (first.offset, last.offset) + } else { + // We have a degenerate gradient and can't accurately transform the stops + // what happens here depends on the repeat behavior, but in any case + // we reconstruct the gradient stops to something simpler and equivalent + stops.clear(); + + match extend_mode { + ExtendMode::Clamp => { + // This gradient is two colors split at the offset of the stops, + // so create a gradient with two colors split at 0.5 and adjust + // the gradient line so 0.5 is at the offset of the stops + stops.push(GradientStop { color: first.color, offset: 0.0, }); + stops.push(GradientStop { color: first.color, offset: 0.5, }); + stops.push(GradientStop { color: last.color, offset: 0.5, }); + stops.push(GradientStop { color: last.color, offset: 1.0, }); + + let offset = last.offset; + + (offset - 0.5, offset + 0.5) + } + ExtendMode::Repeat => { + // A repeating gradient with stops that are all in the same + // position should just display the last color. I believe the + // spec says that it should be the average color of the gradient, + // but this matches what Gecko and Blink does + stops.push(GradientStop { color: last.color, offset: 0.0, }); + stops.push(GradientStop { color: last.color, offset: 1.0, }); + + (0.0, 1.0) + } + } + } + } +} diff --git a/gfx/webrender_api/src/lib.rs b/gfx/webrender_api/src/lib.rs index 2786c2a01510..45bb28e867df 100644 --- a/gfx/webrender_api/src/lib.rs +++ b/gfx/webrender_api/src/lib.rs @@ -33,6 +33,7 @@ mod color; mod display_item; mod display_list; mod font; +mod gradient_builder; mod image; mod units; @@ -41,5 +42,6 @@ pub use color::*; pub use display_item::*; pub use display_list::*; pub use font::*; +pub use gradient_builder::*; pub use image::*; pub use units::*; diff --git a/gfx/webrender_bindings/revision.txt b/gfx/webrender_bindings/revision.txt index 8785163f163c..29c223692905 100644 --- a/gfx/webrender_bindings/revision.txt +++ b/gfx/webrender_bindings/revision.txt @@ -1 +1 @@ -816ff14c1805c145ccd60d0227d82b1541fc24eb +5fa5c46e167ca834d8fec3bf662bf420418698f4 diff --git a/gfx/wrench/src/yaml_frame_writer.rs b/gfx/wrench/src/yaml_frame_writer.rs index 85238a31f090..940aa693d483 100644 --- a/gfx/wrench/src/yaml_frame_writer.rs +++ b/gfx/wrench/src/yaml_frame_writer.rs @@ -228,6 +228,7 @@ fn write_stacking_context( let mut filters = vec![]; for filter in filter_iter { match filter { + FilterOp::Identity => { filters.push(Yaml::String("identity".into())) } FilterOp::Blur(x) => { filters.push(Yaml::String(format!("blur({})", x))) } FilterOp::Brightness(x) => { filters.push(Yaml::String(format!("brightness({})", x))) } FilterOp::Contrast(x) => { filters.push(Yaml::String(format!("contrast({})", x))) } diff --git a/gfx/wrench/src/yaml_helper.rs b/gfx/wrench/src/yaml_helper.rs index ec8b34568a46..3b0f40a5cd41 100644 --- a/gfx/wrench/src/yaml_helper.rs +++ b/gfx/wrench/src/yaml_helper.rs @@ -544,6 +544,9 @@ impl YamlHelper for Yaml { fn as_filter_op(&self) -> Option { if let Some(s) = self.as_str() { match parse_function(s) { + ("identity", _, _) => { + Some(FilterOp::Identity) + } ("blur", ref args, _) if args.len() == 1 => { Some(FilterOp::Blur(args[0].parse().unwrap())) } diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp index 9623f055bcfc..a5b528850c5c 100644 --- a/js/src/ctypes/CTypes.cpp +++ b/js/src/ctypes/CTypes.cpp @@ -38,7 +38,6 @@ #include "ctypes/Library.h" #include "gc/FreeOp.h" #include "gc/Policy.h" -#include "gc/Zone.h" #include "jit/AtomicOperations.h" #include "js/AutoByteString.h" #include "js/StableStringChars.h" diff --git a/js/src/frontend/BinSource-macros.h b/js/src/frontend/BinSource-macros.h index b4077986a5b3..d8586e12edd7 100644 --- a/js/src/frontend/BinSource-macros.h +++ b/js/src/frontend/BinSource-macros.h @@ -7,6 +7,7 @@ #ifndef frontend_BinSource_macros_h #define frontend_BinSource_macros_h +#include "vm/JSContext.h" // Evaluate an expression EXPR, checking that the result is not falsy. // @@ -17,7 +18,6 @@ return cx_->alreadyReportedError(); \ } while(false) - // Evaluate an expression EXPR, checking that the result is not falsy. // In case of success, assign the result to VAR. // diff --git a/js/src/frontend/BinSource.h b/js/src/frontend/BinSource.h index a93ebd7895b2..ccff17b6a54d 100644 --- a/js/src/frontend/BinSource.h +++ b/js/src/frontend/BinSource.h @@ -75,16 +75,15 @@ class BinASTParserBase: private JS::AutoGCRooter LifoAlloc::Mark tempPoolMark_; ParseNodeAllocator nodeAlloc_; + // ---- Parsing-related stuff + protected: // Root atoms and objects allocated for the parse tree. AutoKeepAtoms keepAtoms_; - // ---- Parsing-related stuff - protected: ParseContext* parseContext_; FullParseHandler factory_; friend class BinParseContext; - }; /** diff --git a/js/src/frontend/BinSourceRuntimeSupport.h b/js/src/frontend/BinSourceRuntimeSupport.h index a7401b67812f..4a1ca5e8ce7e 100644 --- a/js/src/frontend/BinSourceRuntimeSupport.h +++ b/js/src/frontend/BinSourceRuntimeSupport.h @@ -8,12 +8,10 @@ #define frontend_BinSourceSupport_h #include "mozilla/HashFunctions.h" -#include "mozilla/Maybe.h" - -#include "jsapi.h" #include "frontend/BinToken.h" +#include "js/AllocPolicy.h" #include "js/HashTable.h" #include "js/Result.h" @@ -21,9 +19,9 @@ namespace js { // Support for parsing JS Binary ASTs. struct BinaryASTSupport { - using BinVariant = js::frontend::BinVariant; + using BinVariant = js::frontend::BinVariant; using BinField = js::frontend::BinField; - using BinKind = js::frontend::BinKind; + using BinKind = js::frontend::BinKind; // A structure designed to perform fast char* + length lookup // without copies. diff --git a/js/src/frontend/BinToken.cpp b/js/src/frontend/BinToken.cpp index 30c31f48fc4a..601f34173b80 100644 --- a/js/src/frontend/BinToken.cpp +++ b/js/src/frontend/BinToken.cpp @@ -10,12 +10,10 @@ #include -#include "jsapi.h" - #include "frontend/BinSourceRuntimeSupport.h" #include "frontend/TokenStream.h" -#include "gc/Zone.h" #include "js/Result.h" +#include "vm/Runtime.h" namespace js { namespace frontend { diff --git a/js/src/frontend/BinTokenReaderBase.cpp b/js/src/frontend/BinTokenReaderBase.cpp index aa5df8cf5489..d56e593977fb 100644 --- a/js/src/frontend/BinTokenReaderBase.cpp +++ b/js/src/frontend/BinTokenReaderBase.cpp @@ -7,7 +7,6 @@ #include "frontend/BinTokenReaderBase.h" #include "frontend/BinSource-macros.h" -#include "gc/Zone.h" #include "js/Result.h" namespace js { @@ -64,6 +63,13 @@ BinTokenReaderBase::raiseInvalidField(const char* kind, const BinField field) return raiseError(out.string()); } +#ifdef DEBUG +bool +BinTokenReaderBase::hasRaisedError() const +{ + return cx_->isExceptionPending(); +} +#endif size_t BinTokenReaderBase::offset() const diff --git a/js/src/frontend/BinTokenReaderBase.h b/js/src/frontend/BinTokenReaderBase.h index 0cb591f6ec10..3633932f3bf0 100644 --- a/js/src/frontend/BinTokenReaderBase.h +++ b/js/src/frontend/BinTokenReaderBase.h @@ -124,7 +124,7 @@ class MOZ_STACK_CLASS BinTokenReaderBase MOZ_MUST_USE bool matchConst(const char (&value)[N], bool expectNul) { MOZ_ASSERT(N > 0); MOZ_ASSERT(value[N - 1] == 0); - MOZ_ASSERT(!cx_->isExceptionPending()); + MOZ_ASSERT(!hasRaisedError()); if (current_ + N - 1 > stop_) return false; @@ -141,6 +141,10 @@ class MOZ_STACK_CLASS BinTokenReaderBase void updateLatestKnownGood(); +#ifdef DEBUG + bool hasRaisedError() const; +#endif + JSContext* cx_; // `true` if we have encountered an error. Errors are non recoverable. diff --git a/js/src/frontend/BinTokenReaderMultipart.cpp b/js/src/frontend/BinTokenReaderMultipart.cpp index 116333667387..ae361a36970a 100644 --- a/js/src/frontend/BinTokenReaderMultipart.cpp +++ b/js/src/frontend/BinTokenReaderMultipart.cpp @@ -16,7 +16,6 @@ #include "frontend/BinSource-macros.h" #include "frontend/BinSourceRuntimeSupport.h" -#include "gc/Zone.h" #include "js/Result.h" namespace js { diff --git a/js/src/frontend/BinTokenReaderMultipart.h b/js/src/frontend/BinTokenReaderMultipart.h index bbcd78f2d458..87bbc5b5a537 100644 --- a/js/src/frontend/BinTokenReaderMultipart.h +++ b/js/src/frontend/BinTokenReaderMultipart.h @@ -9,6 +9,7 @@ #include "mozilla/Maybe.h" +#include "frontend/BinSourceRuntimeSupport.h" #include "frontend/BinToken.h" #include "frontend/BinTokenReaderBase.h" diff --git a/js/src/frontend/BinTokenReaderTester.cpp b/js/src/frontend/BinTokenReaderTester.cpp index c71aedf73a6d..ac0bb7641fb0 100644 --- a/js/src/frontend/BinTokenReaderTester.cpp +++ b/js/src/frontend/BinTokenReaderTester.cpp @@ -13,7 +13,6 @@ #include "mozilla/PodOperations.h" #include "frontend/BinSource-macros.h" -#include "gc/Zone.h" #include "js/Result.h" namespace js { diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 0343d5be3238..84ab1e08c6c0 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -26,8 +26,7 @@ #include "vm/EnvironmentObject-inl.h" #include "vm/GeckoProfiler-inl.h" -#include "vm/JSObject-inl.h" -#include "vm/JSScript-inl.h" +#include "vm/JSContext-inl.h" using namespace js; using namespace js::frontend; diff --git a/js/src/frontend/BytecodeCompiler.h b/js/src/frontend/BytecodeCompiler.h index 11fc62e99e47..c95068a12cfd 100644 --- a/js/src/frontend/BytecodeCompiler.h +++ b/js/src/frontend/BytecodeCompiler.h @@ -13,7 +13,6 @@ #include "js/CompileOptions.h" #include "vm/Scope.h" -#include "vm/StringType.h" #include "vm/TraceLogging.h" class JSLinearString; diff --git a/js/src/frontend/BytecodeControlStructures.h b/js/src/frontend/BytecodeControlStructures.h index 15bab610936c..db2d338c5812 100644 --- a/js/src/frontend/BytecodeControlStructures.h +++ b/js/src/frontend/BytecodeControlStructures.h @@ -19,7 +19,6 @@ #include "frontend/TDZCheckCache.h" #include "gc/Rooting.h" #include "vm/BytecodeUtil.h" -#include "vm/StringType.h" namespace js { namespace frontend { diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index ee70851e4bf4..c5901ff16ec4 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -18,7 +18,6 @@ #include -#include "jsapi.h" #include "jsnum.h" #include "jstypes.h" #include "jsutil.h" @@ -49,10 +48,7 @@ #include "wasm/AsmJS.h" #include "frontend/ParseNode-inl.h" -#include "vm/EnvironmentObject-inl.h" -#include "vm/JSAtom-inl.h" -#include "vm/JSScript-inl.h" -#include "vm/NativeObject-inl.h" +#include "vm/JSObject-inl.h" using namespace js; using namespace js::gc; diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index b975ceaad324..ff700dca4450 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -21,8 +21,6 @@ #include "vm/BytecodeUtil.h" #include "vm/Interpreter.h" #include "vm/Iteration.h" -#include "vm/JSContext.h" -#include "vm/JSScript.h" namespace js { namespace frontend { diff --git a/js/src/frontend/EmitterScope.cpp b/js/src/frontend/EmitterScope.cpp index a40000f60fcc..812c49334688 100644 --- a/js/src/frontend/EmitterScope.cpp +++ b/js/src/frontend/EmitterScope.cpp @@ -10,6 +10,8 @@ #include "frontend/TDZCheckCache.h" #include "js/AutoByteString.h" +#include "vm/GlobalObject.h" + using namespace js; using namespace js::frontend; diff --git a/js/src/frontend/EmitterScope.h b/js/src/frontend/EmitterScope.h index 1373ad7d1f2a..c56c20ecfb7b 100644 --- a/js/src/frontend/EmitterScope.h +++ b/js/src/frontend/EmitterScope.h @@ -18,9 +18,11 @@ #include "frontend/ParseContext.h" #include "frontend/SharedContext.h" #include "js/TypeDecls.h" -#include "vm/Scope.h" namespace js { + +class Scope; + namespace frontend { // A scope that introduces bindings. diff --git a/js/src/frontend/ErrorReporter.h b/js/src/frontend/ErrorReporter.h index 088fb9ddc7e9..03864b942034 100644 --- a/js/src/frontend/ErrorReporter.h +++ b/js/src/frontend/ErrorReporter.h @@ -11,7 +11,10 @@ #include // for size_t #include // for uint32_t -#include "jsapi.h" // for JS::ReadOnlyCompileOptions +#include "js/CompileOptions.h" +#include "js/UniquePtr.h" + +class JSErrorNotes; namespace js { namespace frontend { diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp index 0d8e3005740b..6718d8323530 100644 --- a/js/src/frontend/FoldConstants.cpp +++ b/js/src/frontend/FoldConstants.cpp @@ -9,15 +9,13 @@ #include "mozilla/FloatingPoint.h" #include "jslibmath.h" +#include "jsnum.h" #include "frontend/ParseNode.h" #include "frontend/Parser.h" #include "js/Conversions.h" #include "vm/StringType.h" -#include "vm/JSContext-inl.h" -#include "vm/JSObject-inl.h" - using namespace js; using namespace js::frontend; diff --git a/js/src/frontend/ForOfLoopControl.h b/js/src/frontend/ForOfLoopControl.h index ff9e5293d999..c7137a7fb522 100644 --- a/js/src/frontend/ForOfLoopControl.h +++ b/js/src/frontend/ForOfLoopControl.h @@ -12,8 +12,6 @@ #include -#include "jsapi.h" - #include "frontend/BytecodeControlStructures.h" #include "frontend/TryEmitter.h" #include "vm/Iteration.h" diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index 8a1ee11d2f1d..351f065bd5eb 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -14,6 +14,7 @@ #include "frontend/ParseNode.h" #include "frontend/SharedContext.h" +#include "vm/JSContext.h" namespace js { diff --git a/js/src/frontend/NameCollections.h b/js/src/frontend/NameCollections.h index df14282ae91c..d6f1bd1fdf14 100644 --- a/js/src/frontend/NameCollections.h +++ b/js/src/frontend/NameCollections.h @@ -10,11 +10,12 @@ #include "ds/InlineTable.h" #include "frontend/NameAnalysisTypes.h" #include "js/Vector.h" -#include "vm/Stack.h" namespace js { namespace frontend { +class FunctionBox; + // A pool of recyclable containers for use in the frontend. The Parser and // BytecodeEmitter create many maps for name analysis that are short-lived // (i.e., for the duration of parsing or emitting a lexical scope). Making @@ -162,7 +163,6 @@ using RecyclableNameMap = InlineMap; using DeclaredNameMap = RecyclableNameMap; -using CheckTDZMap = RecyclableNameMap; using NameLocationMap = RecyclableNameMap; using AtomIndexMap = RecyclableNameMap; @@ -335,9 +335,6 @@ class PooledVectorPtr namespace mozilla { -template <> -struct IsPod : TrueType {}; - template struct IsPod> : IsPod {}; diff --git a/js/src/frontend/ParseContext-inl.h b/js/src/frontend/ParseContext-inl.h index be2d22b53b47..fb3c14bd1a86 100644 --- a/js/src/frontend/ParseContext-inl.h +++ b/js/src/frontend/ParseContext-inl.h @@ -1,3 +1,9 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * 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/. */ + #ifndef frontend_ParseContext_inl_h #define frontend_ParseContext_inl_h @@ -20,7 +26,6 @@ ParseContext::Statement::is() const return kind_ == StatementKind::Class; } - inline JS::Result ParseContext::checkBreakStatement(PropertyName* label) { diff --git a/js/src/frontend/ParseContext.h b/js/src/frontend/ParseContext.h index 1a566c825a29..e39ac0410a6b 100644 --- a/js/src/frontend/ParseContext.h +++ b/js/src/frontend/ParseContext.h @@ -486,35 +486,9 @@ class ParseContext : public Nestable bool superScopeNeedsHomeObject_; public: - inline ParseContext(JSContext* cx, ParseContext*& parent, SharedContext* sc, ErrorReporter& errorReporter, - class UsedNameTracker& usedNames, Directives* newDirectives, bool isFull) - : Nestable(&parent), - traceLog_(sc->context, - isFull - ? TraceLogger_ParsingFull - : TraceLogger_ParsingSyntax, - errorReporter), - sc_(sc), - errorReporter_(errorReporter), - innermostStatement_(nullptr), - innermostScope_(nullptr), - varScope_(nullptr), - positionalFormalParameterNames_(cx->frontendCollectionPool()), - closedOverBindingsForLazy_(cx->frontendCollectionPool()), - innerFunctionsForLazy(cx, GCVector(cx)), - newDirectives(newDirectives), - lastYieldOffset(NoYieldOffset), - lastAwaitOffset(NoAwaitOffset), - scriptId_(usedNames.nextScriptId()), - isStandaloneFunctionBody_(false), - superScopeNeedsHomeObject_(false) - { - if (isFunctionBox()) { - if (functionBox()->function()->isNamedLambda()) - namedLambdaScope_.emplace(cx, parent, usedNames); - functionScope_.emplace(cx, parent, usedNames); - } - } + ParseContext(JSContext* cx, ParseContext*& parent, SharedContext* sc, + ErrorReporter& errorReporter, UsedNameTracker& usedNames, + Directives* newDirectives, bool isFull); MOZ_MUST_USE bool init(); diff --git a/js/src/frontend/ParseNode.cpp b/js/src/frontend/ParseNode.cpp index 3325d2f2579e..13a827c709ef 100644 --- a/js/src/frontend/ParseNode.cpp +++ b/js/src/frontend/ParseNode.cpp @@ -8,6 +8,8 @@ #include "mozilla/FloatingPoint.h" +#include "jsnum.h" + #include "frontend/Parser.h" #include "vm/JSContext-inl.h" diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index ed5b8d72ae2e..0e6aba52191f 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -9,9 +9,10 @@ #include "mozilla/Attributes.h" -#include "builtin/ModuleObject.h" #include "frontend/TokenStream.h" +#include "vm/BytecodeUtil.h" #include "vm/Printer.h" +#include "vm/Scope.h" // A few notes on lifetime of ParseNode trees: // diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 9f5e60be4618..1cef13f01011 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -28,7 +28,7 @@ #include #include -#include "jsapi.h" +#include "jsnum.h" #include "jstypes.h" #include "builtin/ModuleObject.h" @@ -50,8 +50,6 @@ #include "frontend/ParseContext-inl.h" #include "frontend/ParseNode-inl.h" #include "vm/EnvironmentObject-inl.h" -#include "vm/JSAtom-inl.h" -#include "vm/JSScript-inl.h" using namespace js; using namespace js::gc; @@ -380,6 +378,37 @@ EvalSharedContext::EvalSharedContext(JSContext* cx, JSObject* enclosingEnv, } } +ParseContext::ParseContext(JSContext* cx, ParseContext*& parent, SharedContext* sc, + ErrorReporter& errorReporter, class UsedNameTracker& usedNames, + Directives* newDirectives, bool isFull) + : Nestable(&parent), + traceLog_(sc->context, + isFull + ? TraceLogger_ParsingFull + : TraceLogger_ParsingSyntax, + errorReporter), + sc_(sc), + errorReporter_(errorReporter), + innermostStatement_(nullptr), + innermostScope_(nullptr), + varScope_(nullptr), + positionalFormalParameterNames_(cx->frontendCollectionPool()), + closedOverBindingsForLazy_(cx->frontendCollectionPool()), + innerFunctionsForLazy(cx, GCVector(cx)), + newDirectives(newDirectives), + lastYieldOffset(NoYieldOffset), + lastAwaitOffset(NoAwaitOffset), + scriptId_(usedNames.nextScriptId()), + isStandaloneFunctionBody_(false), + superScopeNeedsHomeObject_(false) +{ + if (isFunctionBox()) { + if (functionBox()->function()->isNamedLambda()) + namedLambdaScope_.emplace(cx, parent, usedNames); + functionScope_.emplace(cx, parent, usedNames); + } +} + bool ParseContext::init() { @@ -462,6 +491,14 @@ UsedNameTracker::rewind(RewindToken token) r.front().value().resetToScope(token.scriptId, token.scopeId); } +#ifdef DEBUG +bool +FunctionBox::atomsAreKept() +{ + return context->zone()->hasKeptAtoms(); +} +#endif + FunctionBox::FunctionBox(JSContext* cx, ObjectBox* traceListHead, JSFunction* fun, uint32_t toStringStart, Directives directives, bool extraWarnings, diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 15ce01e509f8..519643ad41d6 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -181,8 +181,6 @@ #include "frontend/SharedContext.h" #include "frontend/SyntaxParseHandler.h" #include "frontend/TokenStream.h" -#include "js/CompileOptions.h" -#include "vm/Iteration.h" namespace js { diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h index 41f442d1f1e5..692ba5b381d3 100644 --- a/js/src/frontend/SharedContext.h +++ b/js/src/frontend/SharedContext.h @@ -14,10 +14,8 @@ #include "ds/InlineTable.h" #include "frontend/ParseNode.h" #include "frontend/TokenStream.h" -#include "gc/Zone.h" #include "vm/BytecodeUtil.h" -#include "vm/EnvironmentObject.h" -#include "vm/JSAtom.h" +#include "vm/JSFunction.h" #include "vm/JSScript.h" namespace js { @@ -410,18 +408,22 @@ class FunctionBox : public ObjectBox, public SharedContext uint32_t toStringStart, Directives directives, bool extraWarnings, GeneratorKind generatorKind, FunctionAsyncKind asyncKind); +#ifdef DEBUG + bool atomsAreKept(); +#endif + MutableHandle namedLambdaBindings() { - MOZ_ASSERT(context->zone()->hasKeptAtoms()); + MOZ_ASSERT(atomsAreKept()); return MutableHandle::fromMarkedLocation(&namedLambdaBindings_); } MutableHandle functionScopeBindings() { - MOZ_ASSERT(context->zone()->hasKeptAtoms()); + MOZ_ASSERT(atomsAreKept()); return MutableHandle::fromMarkedLocation(&functionScopeBindings_); } MutableHandle extraVarScopeBindings() { - MOZ_ASSERT(context->zone()->hasKeptAtoms()); + MOZ_ASSERT(atomsAreKept()); return MutableHandle::fromMarkedLocation(&extraVarScopeBindings_); } diff --git a/js/src/frontend/TDZCheckCache.h b/js/src/frontend/TDZCheckCache.h index 29ccefda1485..19407b160c1b 100644 --- a/js/src/frontend/TDZCheckCache.h +++ b/js/src/frontend/TDZCheckCache.h @@ -20,6 +20,8 @@ namespace frontend { struct BytecodeEmitter; +using CheckTDZMap = RecyclableNameMap; + // A cache that tracks Temporal Dead Zone (TDZ) checks, so that any use of a // lexical variable that's dominated by an earlier use, or by evaluation of its // declaration (which will initialize it, perhaps to |undefined|), doesn't have diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index 6c1a56de6f2b..796bf0225231 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -210,13 +210,17 @@ #include "util/Text.h" #include "util/Unicode.h" #include "vm/ErrorReporting.h" -#include "vm/JSContext.h" -#include "vm/RegExpShared.h" +#include "vm/JSAtom.h" +#include "vm/RegExpConstants.h" #include "vm/StringType.h" +struct JSContext; struct KeywordInfo; namespace js { + +class AutoKeepAtoms; + namespace frontend { struct TokenPos { diff --git a/js/src/gc/GC.cpp b/js/src/gc/GC.cpp index 6dcdccfcccbd..6290b7d2993c 100644 --- a/js/src/gc/GC.cpp +++ b/js/src/gc/GC.cpp @@ -2532,7 +2532,7 @@ Zone::prepareForCompacting() void GCRuntime::sweepTypesAfterCompacting(Zone* zone) { - zone->beginSweepTypes(rt->gc.releaseObservedTypes && !zone->isPreservingCode()); + zone->beginSweepTypes(releaseObservedTypes && !zone->isPreservingCode()); AutoClearTypeInferenceStateOnOOM oom(zone); @@ -2948,7 +2948,7 @@ GCRuntime::updateZonePointersToRelocatedCells(Zone* zone) } // Sweep everything to fix up weak pointers. - rt->gc.sweepZoneAfterCompacting(zone); + sweepZoneAfterCompacting(zone); // Call callbacks to get the rest of the system to fixup other untraced pointers. for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) @@ -3642,7 +3642,7 @@ GCRuntime::sweepBackgroundThings(ZoneList& zones, LifoAlloc& freeBlocks) // sweeping finished. Now we must update this value. arena->zone->threshold.updateForRemovedArena(tunables); - rt->gc.releaseArena(arena, lock); + releaseArena(arena, lock); releaseCount++; if (releaseCount % LockReleasePeriod == 0) { lock.unlock(); @@ -3763,33 +3763,39 @@ BackgroundSweepTask::run() MOZ_ASSERT(!done); - JSRuntime* rt = runtime(); - - // The main thread may call queueZonesForBackgroundSweep() while this is - // running so we must check there is no more work after releasing the lock. - do { - ZoneList zones; - zones.transferFrom(rt->gc.backgroundSweepZones.ref()); - LifoAlloc freeLifoAlloc(JSContext::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE); - freeLifoAlloc.transferFrom(&rt->gc.blocksToFreeAfterSweeping.ref()); - - AutoUnlockHelperThreadState unlock(lock); - rt->gc.sweepBackgroundThings(zones, freeLifoAlloc); - } while (!rt->gc.backgroundSweepZones.ref().isEmpty()); + runtime()->gc.sweepFromBackgroundThread(lock); // Signal to the main thread that we're finished, because we release the // lock again before GCParallelTask's state is changed to finished. done = true; } +void +GCRuntime::sweepFromBackgroundThread(AutoLockHelperThreadState& lock) +{ + do { + ZoneList zones; + zones.transferFrom(backgroundSweepZones.ref()); + LifoAlloc freeLifoAlloc(JSContext::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE); + freeLifoAlloc.transferFrom(&blocksToFreeAfterSweeping.ref()); + + AutoUnlockHelperThreadState unlock(lock); + sweepBackgroundThings(zones, freeLifoAlloc); + + // The main thread may call queueZonesForBackgroundSweep() while this is + // running so we must check there is no more work after releasing the + // lock. + } while (!backgroundSweepZones.ref().isEmpty()); +} + void GCRuntime::waitBackgroundSweepEnd() { sweepTask.join(); // TODO: Improve assertion to work in incremental GC? - if (!rt->gc.isIncrementalGCInProgress()) - rt->gc.assertBackgroundSweepingFinished(); + if (!isIncrementalGCInProgress()) + assertBackgroundSweepingFinished(); } bool @@ -3954,7 +3960,7 @@ GCRuntime::sweepZones(FreeOp* fop, bool destroyingRuntime) MOZ_ASSERT_IF(destroyingRuntime, numActiveZoneIters == 0); MOZ_ASSERT_IF(destroyingRuntime, arenasEmptyAtShutdown); - if (rt->gc.numActiveZoneIters) + if (numActiveZoneIters) return; assertBackgroundSweepingFinished(); @@ -5162,7 +5168,7 @@ GCRuntime::getNextSweepGroup() * push the referring object onto the list. * * The list is traversed and then unlinked in - * MarkIncomingCrossCompartmentPointers. + * GCRuntime::markIncomingCrossCompartmentPointers. */ static bool @@ -5256,8 +5262,8 @@ js::gc::DelayCrossCompartmentGrayMarking(JSObject* src) #endif } -static void -MarkIncomingCrossCompartmentPointers(JSRuntime* rt, MarkColor color) +void +GCRuntime::markIncomingCrossCompartmentPointers(MarkColor color) { MOZ_ASSERT(color == MarkColor::Black || color == MarkColor::Gray); @@ -5265,7 +5271,7 @@ MarkIncomingCrossCompartmentPointers(JSRuntime* rt, MarkColor color) gcstats::PhaseKind::SWEEP_MARK_INCOMING_BLACK, gcstats::PhaseKind::SWEEP_MARK_INCOMING_GRAY }; - gcstats::AutoPhase ap1(rt->gc.stats(), statsPhases[unsigned(color)]); + gcstats::AutoPhase ap1(stats(), statsPhases[unsigned(color)]); bool unlinkList = color == MarkColor::Gray; @@ -5283,11 +5289,11 @@ MarkIncomingCrossCompartmentPointers(JSRuntime* rt, MarkColor color) if (color == MarkColor::Gray) { if (IsMarkedUnbarriered(rt, &src) && src->asTenured().isMarkedGray()) - TraceManuallyBarrieredEdge(&rt->gc.marker, &dst, + TraceManuallyBarrieredEdge(&marker, &dst, "cross-compartment gray pointer"); } else { if (IsMarkedUnbarriered(rt, &src) && !src->asTenured().isMarkedGray()) - TraceManuallyBarrieredEdge(&rt->gc.marker, &dst, + TraceManuallyBarrieredEdge(&marker, &dst, "cross-compartment black pointer"); } } @@ -5297,7 +5303,7 @@ MarkIncomingCrossCompartmentPointers(JSRuntime* rt, MarkColor color) } auto unlimited = SliceBudget::unlimited(); - MOZ_RELEASE_ASSERT(rt->gc.marker.drainMarkStack(unlimited)); + MOZ_RELEASE_ASSERT(marker.drainMarkStack(unlimited)); } static bool @@ -5394,7 +5400,7 @@ GCRuntime::endMarkingSweepGroup(FreeOp* fop, SliceBudget& budget) * whose referents are not marked. This can occur when gray cells become * black by the action of UnmarkGray. */ - MarkIncomingCrossCompartmentPointers(rt, MarkColor::Black); + markIncomingCrossCompartmentPointers(MarkColor::Black); markWeakReferencesInCurrentGroup(gcstats::PhaseKind::SWEEP_MARK_WEAK); /* @@ -5408,7 +5414,7 @@ GCRuntime::endMarkingSweepGroup(FreeOp* fop, SliceBudget& budget) marker.setMarkColorGray(); /* Mark incoming gray pointers from previously swept compartments. */ - MarkIncomingCrossCompartmentPointers(rt, MarkColor::Gray); + markIncomingCrossCompartmentPointers(MarkColor::Gray); /* Mark gray roots and mark transitively inside the current compartment group. */ markGrayReferencesInCurrentGroup(gcstats::PhaseKind::SWEEP_MARK_GRAY); @@ -6960,7 +6966,7 @@ GCRuntime::resetIncrementalGC(gc::AbortReason reason, AutoGCSession& session) { gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::WAIT_BACKGROUND_THREAD); - rt->gc.waitBackgroundSweepOrAllocEnd(); + waitBackgroundSweepOrAllocEnd(); } break; } @@ -6968,7 +6974,7 @@ GCRuntime::resetIncrementalGC(gc::AbortReason reason, AutoGCSession& session) case State::Finalize: { { gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::WAIT_BACKGROUND_THREAD); - rt->gc.waitBackgroundSweepOrAllocEnd(); + waitBackgroundSweepOrAllocEnd(); } bool wasCompacting = isCompacting; @@ -7432,21 +7438,21 @@ class AutoScheduleZonesForGC JSRuntime* rt_; public: - explicit AutoScheduleZonesForGC(JSRuntime* rt) : rt_(rt) { - for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) { + explicit AutoScheduleZonesForGC(GCRuntime* gc) : rt_(gc->rt) { + for (ZonesIter zone(rt_, WithAtoms); !zone.done(); zone.next()) { if (!zone->canCollect()) continue; - if (rt->gc.gcMode() == JSGC_MODE_GLOBAL) + if (gc->gcMode() == JSGC_MODE_GLOBAL) zone->scheduleGC(); // To avoid resets, continue to collect any zones that were being // collected in a previous slice. - if (rt->gc.isIncrementalGCInProgress() && zone->wasGCStarted()) + if (gc->isIncrementalGCInProgress() && zone->wasGCStarted()) zone->scheduleGC(); // This is a heuristic to reduce the total number of collections. - bool inHighFrequencyMode = rt->gc.schedulingState.inHighFrequencyGCMode(); + bool inHighFrequencyMode = gc->schedulingState.inHighFrequencyGCMode(); if (zone->usage.gcBytes() >= zone->threshold.eagerAllocTrigger(inHighFrequencyMode)) zone->scheduleGC(); @@ -7739,7 +7745,7 @@ GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::R AutoTraceLog logGC(TraceLoggerForCurrentThread(), TraceLogger_GC); AutoStopVerifyingBarriers av(rt, IsShutdownGC(reason)); AutoEnqueuePendingParseTasksAfterGC aept(*this); - AutoScheduleZonesForGC asz(rt); + AutoScheduleZonesForGC asz(this); bool repeat; do { @@ -7782,11 +7788,11 @@ GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::R maybeDoCycleCollection(); #ifdef JS_GC_ZEAL - if (rt->hasZealMode(ZealMode::CheckHeapAfterGC)) { - gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::TRACE_HEAP); + if (hasZealMode(ZealMode::CheckHeapAfterGC)) { + gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::TRACE_HEAP); CheckHeapAfterGC(rt); } - if (rt->hasZealMode(ZealMode::CheckGrayMarking) && !isIncrementalGCInProgress()) { + if (hasZealMode(ZealMode::CheckGrayMarking) && !isIncrementalGCInProgress()) { MOZ_RELEASE_ASSERT(CheckGrayMarkingState(rt)); } #endif @@ -7959,9 +7965,9 @@ GCRuntime::minorGC(JS::gcreason::Reason reason, gcstats::PhaseKind phase) uint32_t numAllocs = rt->mainContextFromOwnThread()->getAndResetAllocsThisZoneSinceMinorGC(); for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) numAllocs += zone->getAndResetTenuredAllocsSinceMinorGC(); - rt->gc.stats().setAllocsSinceMinorGCTenured(numAllocs); + stats().setAllocsSinceMinorGCTenured(numAllocs); - gcstats::AutoPhase ap(rt->gc.stats(), phase); + gcstats::AutoPhase ap(stats(), phase); nursery().clearMinorGCRequest(); TraceLoggerThread* logger = TraceLoggerForCurrentThread(); @@ -7972,7 +7978,7 @@ GCRuntime::minorGC(JS::gcreason::Reason reason, gcstats::PhaseKind phase) blocksToFreeAfterMinorGC.ref().freeAll(); #ifdef JS_GC_ZEAL - if (rt->hasZealMode(ZealMode::CheckHeapAfterGC)) + if (hasZealMode(ZealMode::CheckHeapAfterGC)) CheckHeapAfterGC(rt); #endif diff --git a/js/src/gc/GCInternals.h b/js/src/gc/GCInternals.h index d02153ec6c3f..89280e6386b4 100644 --- a/js/src/gc/GCInternals.h +++ b/js/src/gc/GCInternals.h @@ -16,7 +16,6 @@ #include "gc/GC.h" #include "gc/RelocationOverlay.h" -#include "gc/Zone.h" #include "vm/HelperThreads.h" #include "vm/Runtime.h" @@ -321,7 +320,7 @@ IsOOMReason(JS::gcreason::Reason reason) } TenuredCell* -AllocateCellInGC(Zone* zone, AllocKind thingKind); +AllocateCellInGC(JS::Zone* zone, AllocKind thingKind); } /* namespace gc */ } /* namespace js */ diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index b677ce44bcfb..dbdd57b380e6 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -624,6 +624,7 @@ class GCRuntime MOZ_MUST_USE bool findInterZoneEdges(); void getNextSweepGroup(); IncrementalProgress endMarkingSweepGroup(FreeOp* fop, SliceBudget& budget); + void markIncomingCrossCompartmentPointers(MarkColor color); IncrementalProgress beginSweepingSweepGroup(FreeOp* fop, SliceBudget& budget); #ifdef JS_GC_ZEAL IncrementalProgress maybeYieldForSweepingZeal(FreeOp* fop, SliceBudget& budget); @@ -648,6 +649,7 @@ class GCRuntime void startDecommit(); void queueZonesForBackgroundSweep(ZoneList& zones); void maybeStartBackgroundSweep(AutoLockHelperThreadState& lock); + void sweepFromBackgroundThread(AutoLockHelperThreadState& lock); void sweepBackgroundThings(ZoneList& zones, LifoAlloc& freeBlocks); void assertBackgroundSweepingFinished(); bool shouldCompact(); diff --git a/js/src/gc/Rooting.h b/js/src/gc/Rooting.h index e94f1af7a03b..0e081f2c49ca 100644 --- a/js/src/gc/Rooting.h +++ b/js/src/gc/Rooting.h @@ -30,6 +30,7 @@ class DebuggerEnvironment; class DebuggerFrame; class DebuggerObject; class Scope; +class ModuleObject; // These are internal counterparts to the public types such as HandleObject. @@ -48,6 +49,7 @@ typedef JS::Handle HandleDebuggerEnvironment; typedef JS::Handle HandleDebuggerFrame; typedef JS::Handle HandleDebuggerObject; typedef JS::Handle HandleScope; +typedef JS::Handle HandleModuleObject; typedef JS::MutableHandle MutableHandleShape; typedef JS::MutableHandle MutableHandleAtom; @@ -59,6 +61,7 @@ typedef JS::MutableHandle MutableHandleDebuggerEnvironment typedef JS::MutableHandle MutableHandleDebuggerFrame; typedef JS::MutableHandle MutableHandleDebuggerObject; typedef JS::MutableHandle MutableHandleScope; +typedef JS::MutableHandle MutableHandleModuleObject; typedef JS::Rooted RootedNativeObject; typedef JS::Rooted RootedShape; @@ -76,6 +79,7 @@ typedef JS::Rooted RootedDebuggerEnvironment; typedef JS::Rooted RootedDebuggerFrame; typedef JS::Rooted RootedDebuggerObject; typedef JS::Rooted RootedScope; +typedef JS::Rooted RootedModuleObject; typedef JS::GCVector FunctionVector; typedef JS::GCVector PropertyNameVector; diff --git a/js/src/gc/WeakMap-inl.h b/js/src/gc/WeakMap-inl.h index 10affa40b699..1061c8cf51b7 100644 --- a/js/src/gc/WeakMap-inl.h +++ b/js/src/gc/WeakMap-inl.h @@ -9,7 +9,6 @@ #include "gc/WeakMap.h" -#include "gc/Zone.h" #include "vm/JSContext.h" namespace js { diff --git a/js/src/jit-test/tests/modules/bug1485698.js b/js/src/jit-test/tests/modules/bug1485698.js new file mode 100644 index 000000000000..36bbda1c8b59 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug1485698.js @@ -0,0 +1,9 @@ +let m = parseModule(` + function f(x,y,z) { + delete arguments[2]; + import.meta[2] + } + f(1,2,3) +`); +instantiateModule(m); +evaluateModule(m); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 1260cce8117c..fd00051c165c 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -13169,10 +13169,20 @@ IonBuilder::jsop_implicitthis(PropertyName* name) AbortReasonOr IonBuilder::jsop_importmeta() { + if (info().analysisMode() == Analysis_ArgumentsUsage) { + // The meta object may not have been created yet. Just push a dummy + // value, it does not affect the arguments analysis. + MUnknownValue* unknown = MUnknownValue::New(alloc()); + current->add(unknown); + current->push(unknown); + return Ok(); + } + ModuleObject* module = GetModuleObjectForScript(script()); MOZ_ASSERT(module); - // The object must have been created already when we compiled for baseline. + // If we get there then the meta object must already have been created, at + // the latest when we compiled for baseline. JSObject* metaObject = module->metaObject(); MOZ_ASSERT(metaObject); diff --git a/js/src/jsapi-tests/testBinASTReader.cpp b/js/src/jsapi-tests/testBinASTReader.cpp index ced2401bc753..64749d4870f1 100644 --- a/js/src/jsapi-tests/testBinASTReader.cpp +++ b/js/src/jsapi-tests/testBinASTReader.cpp @@ -27,7 +27,6 @@ #include "frontend/FullParseHandler.h" #include "frontend/ParseContext.h" #include "frontend/Parser.h" -#include "gc/Zone.h" #include "js/Vector.h" #include "jsapi-tests/tests.h" diff --git a/js/src/jsapi-tests/testBinTokenReaderTester.cpp b/js/src/jsapi-tests/testBinTokenReaderTester.cpp index f0683728fe7d..c2695ad1709d 100644 --- a/js/src/jsapi-tests/testBinTokenReaderTester.cpp +++ b/js/src/jsapi-tests/testBinTokenReaderTester.cpp @@ -18,7 +18,6 @@ #include "mozilla/Maybe.h" #include "frontend/BinTokenReaderTester.h" -#include "gc/Zone.h" #include "js/Vector.h" diff --git a/js/src/jsapi-tests/testErrorInterceptor.cpp b/js/src/jsapi-tests/testErrorInterceptor.cpp index 71a446f5b726..ab88abdfa233 100644 --- a/js/src/jsapi-tests/testErrorInterceptor.cpp +++ b/js/src/jsapi-tests/testErrorInterceptor.cpp @@ -8,8 +8,6 @@ namespace { -const double EXN_VALUE = 3.14; - static JS::PersistentRootedString gLatestMessage; // An interceptor that stores the error in `gLatestMessage`. diff --git a/js/src/jsapi-tests/testGCUniqueId.cpp b/js/src/jsapi-tests/testGCUniqueId.cpp index 945c4c7a6bc1..2706218d3d82 100644 --- a/js/src/jsapi-tests/testGCUniqueId.cpp +++ b/js/src/jsapi-tests/testGCUniqueId.cpp @@ -6,7 +6,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "gc/GCInternals.h" -#include "gc/Zone.h" #include "js/GCVector.h" #include "jsapi-tests/tests.h" diff --git a/js/src/jsapi-tests/testGCWeakRef.cpp b/js/src/jsapi-tests/testGCWeakRef.cpp index f51e7febc766..585db57a9770 100644 --- a/js/src/jsapi-tests/testGCWeakRef.cpp +++ b/js/src/jsapi-tests/testGCWeakRef.cpp @@ -6,7 +6,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "gc/Barrier.h" -#include "gc/Zone.h" #include "js/RootingAPI.h" #include "jsapi-tests/tests.h" diff --git a/js/src/jsapi-tests/testIsInsideNursery.cpp b/js/src/jsapi-tests/testIsInsideNursery.cpp index 618b3c4d1637..d942fc21b481 100644 --- a/js/src/jsapi-tests/testIsInsideNursery.cpp +++ b/js/src/jsapi-tests/testIsInsideNursery.cpp @@ -5,7 +5,6 @@ * 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/. */ -#include "gc/Zone.h" #include "jsapi-tests/tests.h" #include "vm/JSContext-inl.h" diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index 88a3d67711b3..af0491ba789e 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -219,7 +219,7 @@ JS_ScriptHasMutedErrors(JSScript* script) } JS_FRIEND_API(bool) -JS_WrapPropertyDescriptor(JSContext* cx, JS::MutableHandle desc) +JS_WrapPropertyDescriptor(JSContext* cx, JS::MutableHandle desc) { return cx->compartment()->wrap(cx, desc); } diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index a0aaaf32184d..06d2373723e8 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -71,7 +71,6 @@ #endif // defined(JS_BUILD_BINAST) #include "frontend/Parser.h" #include "gc/PublicIterators.h" -#include "gc/Zone.h" #include "jit/arm/Simulator-arm.h" #include "jit/InlinableNatives.h" #include "jit/Ion.h" @@ -719,7 +718,7 @@ GetLine(FILE* file, const char * prompt) if (*t == '\n') { /* Line was read. We remove '\n' and exit. */ *t = '\0'; - return buffer; + break; } if (len + 1 == size) { @@ -733,7 +732,7 @@ GetLine(FILE* file, const char * prompt) } current = buffer + len; } while (true); - return nullptr; + return buffer; } static bool @@ -4310,7 +4309,7 @@ EnsureModuleLoaderScriptObjectMap(JSContext* cx) if (priv->moduleLoaderScriptObjectMap) return priv->moduleLoaderScriptObjectMap.get(); - Zone* zone = cx->zone(); + JS::Zone* zone = cx->zone(); auto* map = cx->new_(zone); if (!map) return nullptr; @@ -7222,7 +7221,9 @@ WasmLoop(JSContext* cx, unsigned argc, Value* vp) } } +#ifdef __AFL_HAVE_MANUAL_CONTROL // to silence unreachable code warning return true; +#endif } static const JSFunctionSpecWithHelp shell_functions[] = { diff --git a/js/src/vm/Compartment.cpp b/js/src/vm/Compartment.cpp index a6db4c09e062..35b789593913 100644 --- a/js/src/vm/Compartment.cpp +++ b/js/src/vm/Compartment.cpp @@ -348,7 +348,7 @@ Compartment::rewrap(JSContext* cx, MutableHandleObject obj, HandleObject existin } bool -Compartment::wrap(JSContext* cx, MutableHandle desc) +Compartment::wrap(JSContext* cx, MutableHandle desc) { if (!wrap(cx, desc.object())) return false; diff --git a/js/src/vm/Compartment.h b/js/src/vm/Compartment.h index eb8838d1a571..8dd5cb3f7f54 100644 --- a/js/src/vm/Compartment.h +++ b/js/src/vm/Compartment.h @@ -17,13 +17,14 @@ #include "gc/Barrier.h" #include "gc/NurseryAwareHashMap.h" -#include "gc/Zone.h" #include "js/UniquePtr.h" +#include "vm/JSObject.h" +#include "vm/JSScript.h" namespace js { namespace gc { -template class ComponentFinder; +struct ZoneComponentFinder; } // namespace gc class CrossCompartmentKey @@ -446,7 +447,7 @@ class JS::Compartment MOZ_MUST_USE bool wrap(JSContext* cx, js::MutableHandle bi); #endif MOZ_MUST_USE bool wrap(JSContext* cx, JS::MutableHandleObject obj); - MOZ_MUST_USE bool wrap(JSContext* cx, JS::MutableHandle desc); + MOZ_MUST_USE bool wrap(JSContext* cx, JS::MutableHandle desc); MOZ_MUST_USE bool wrap(JSContext* cx, JS::MutableHandle> vec); MOZ_MUST_USE bool rewrap(JSContext* cx, JS::MutableHandleObject obj, JS::HandleObject existing); diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index 2c0bdffb965e..9c22478d91ca 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -17,7 +17,6 @@ #include "vm/ErrorObject.h" #include "vm/JSFunction.h" #include "vm/Realm.h" -#include "vm/RegExpStatics.h" #include "vm/Runtime.h" namespace js { @@ -25,6 +24,7 @@ namespace js { class Debugger; class TypedObjectModuleObject; class LexicalEnvironmentObject; +class RegExpStatics; /* * Global object slots are reserved as follows: diff --git a/js/src/vm/Iteration.h b/js/src/vm/Iteration.h index b4cd16797fbd..33b68e356230 100644 --- a/js/src/vm/Iteration.h +++ b/js/src/vm/Iteration.h @@ -15,7 +15,6 @@ #include "mozilla/MemoryReporting.h" #include "gc/Barrier.h" -#include "vm/JSContext.h" #include "vm/ReceiverGuard.h" #include "vm/Stack.h" diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index 4bac9ba3b711..717d419ceab5 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -16,7 +16,6 @@ #include "gc/HashUtil.h" #include "gc/Policy.h" #include "gc/StoreBuffer.h" -#include "gc/Zone.h" #include "js/CharacterEncoding.h" #include "js/UniquePtr.h" #include "vm/ArrayObject.h" diff --git a/js/src/vm/Realm.h b/js/src/vm/Realm.h index f94b66b13592..53f5236065f8 100644 --- a/js/src/vm/Realm.h +++ b/js/src/vm/Realm.h @@ -20,7 +20,6 @@ #include "builtin/Array.h" #include "gc/Barrier.h" -#include "gc/Zone.h" #include "js/UniquePtr.h" #include "vm/ArrayBufferObject.h" #include "vm/Compartment.h" diff --git a/js/src/vm/RegExpConstants.h b/js/src/vm/RegExpConstants.h new file mode 100644 index 000000000000..983983eadbe2 --- /dev/null +++ b/js/src/vm/RegExpConstants.h @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * 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/. */ + +#ifndef vm_RegExpConstants_h +#define vm_RegExpConstants_h + +#include "builtin/SelfHostingDefines.h" + +namespace js { + +enum RegExpFlag : uint8_t +{ + IgnoreCaseFlag = 0x01, + GlobalFlag = 0x02, + MultilineFlag = 0x04, + StickyFlag = 0x08, + UnicodeFlag = 0x10, + + NoFlags = 0x00, + AllFlags = 0x1f +}; + +static_assert(IgnoreCaseFlag == REGEXP_IGNORECASE_FLAG && + GlobalFlag == REGEXP_GLOBAL_FLAG && + MultilineFlag == REGEXP_MULTILINE_FLAG && + StickyFlag == REGEXP_STICKY_FLAG && + UnicodeFlag == REGEXP_UNICODE_FLAG, + "Flag values should be in sync with self-hosted JS"); + +enum RegExpRunStatus +{ + RegExpRunStatus_Error, + RegExpRunStatus_Success, + RegExpRunStatus_Success_NotFound +}; + +} /* namespace js */ + +#endif /* vm_RegExpConstants_h */ diff --git a/js/src/vm/RegExpShared.h b/js/src/vm/RegExpShared.h index 6f935a670cfe..289c6fe83eb5 100644 --- a/js/src/vm/RegExpShared.h +++ b/js/src/vm/RegExpShared.h @@ -15,7 +15,6 @@ #include "mozilla/Assertions.h" #include "mozilla/MemoryReporting.h" -#include "builtin/SelfHostingDefines.h" #include "gc/Barrier.h" #include "gc/Heap.h" #include "gc/Marking.h" @@ -25,6 +24,7 @@ #include "js/Vector.h" #include "vm/ArrayObject.h" #include "vm/JSAtom.h" +#include "vm/RegExpConstants.h" namespace js { @@ -38,32 +38,6 @@ using RootedRegExpShared = JS::Rooted; using HandleRegExpShared = JS::Handle; using MutableHandleRegExpShared = JS::MutableHandle; -enum RegExpFlag : uint8_t -{ - IgnoreCaseFlag = 0x01, - GlobalFlag = 0x02, - MultilineFlag = 0x04, - StickyFlag = 0x08, - UnicodeFlag = 0x10, - - NoFlags = 0x00, - AllFlags = 0x1f -}; - -static_assert(IgnoreCaseFlag == REGEXP_IGNORECASE_FLAG && - GlobalFlag == REGEXP_GLOBAL_FLAG && - MultilineFlag == REGEXP_MULTILINE_FLAG && - StickyFlag == REGEXP_STICKY_FLAG && - UnicodeFlag == REGEXP_UNICODE_FLAG, - "Flag values should be in sync with self-hosted JS"); - -enum RegExpRunStatus -{ - RegExpRunStatus_Error, - RegExpRunStatus_Success, - RegExpRunStatus_Success_NotFound -}; - /* * A RegExpShared is the compiled representation of a regexp. A RegExpShared is * potentially pointed to by multiple RegExpObjects. Additionally, C++ code may diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 038bb8b6fbf3..84f911f12b46 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -103,8 +103,17 @@ class Instance; enum MaybeCheckAliasing { CHECK_ALIASING = true, DONT_CHECK_ALIASING = false }; enum MaybeCheckTDZ { CheckTDZ = true, DontCheckTDZ = false }; +} // namespace js + +namespace mozilla { +template <> +struct IsPod : TrueType {}; +} // namespace mozilla + /*****************************************************************************/ +namespace js { + namespace jit { class BaselineFrame; class RematerializedFrame; @@ -2429,4 +2438,5 @@ FrameIter::physicalJitFrame() const } } /* namespace js */ + #endif /* vm_Stack_h */ diff --git a/js/src/vm/UnboxedObject.h b/js/src/vm/UnboxedObject.h index 8dc911596952..dd1ffe5776ed 100644 --- a/js/src/vm/UnboxedObject.h +++ b/js/src/vm/UnboxedObject.h @@ -8,7 +8,6 @@ #define vm_UnboxedObject_h #include "gc/DeletePolicy.h" -#include "gc/Zone.h" #include "vm/JSObject.h" #include "vm/Runtime.h" #include "vm/TypeInference.h" @@ -59,7 +58,7 @@ class UnboxedLayout : public mozilla::LinkedListElement typedef Vector PropertyVector; private: - Zone* zone_; + JS::Zone* zone_; // If objects in this group have ever been converted to native objects, // these store the corresponding native group and initial shape for such @@ -99,13 +98,13 @@ class UnboxedLayout : public mozilla::LinkedListElement GCPtrJitCode constructorCode_; public: - explicit UnboxedLayout(Zone* zone) + explicit UnboxedLayout(JS::Zone* zone) : zone_(zone), nativeGroup_(nullptr), nativeShape_(nullptr), allocationScript_(nullptr), allocationPc_(nullptr), replacementGroup_(nullptr), size_(0), newScript_(nullptr), traceList_(nullptr), constructorCode_(nullptr) {} - Zone* zone() const { return zone_; } + JS::Zone* zone() const { return zone_; } bool initProperties(const PropertyVector& properties, size_t size) { size_ = size; diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index d05d0ee6d63c..91a5b664ba9c 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -766,8 +766,8 @@ void nsImageFrame::InvalidateSelf(const nsIntRect* aLayerInvalidRect, const nsRect* aFrameInvalidRect) { - // XXX: Do we really want to check whether we have a - // WebRenderUserDataProperty? + // Check if WebRender has interacted with this frame. If it has + // we need to let it know that things have changed. if (HasProperty(WebRenderUserDataProperty::Key())) { RefPtr data = GetWebRenderUserData(this, static_cast(DisplayItemType::TYPE_IMAGE)); if (data) { diff --git a/layout/xul/nsImageBoxFrame.cpp b/layout/xul/nsImageBoxFrame.cpp index 64cce6e02eaf..8b5a093296d6 100644 --- a/layout/xul/nsImageBoxFrame.cpp +++ b/layout/xul/nsImageBoxFrame.cpp @@ -902,6 +902,19 @@ nsImageBoxFrame::OnFrameUpdate(imgIRequest* aRequest) return NS_OK; } + // Check if WebRender has interacted with this frame. If it has + // we need to let it know that things have changed. + if (HasProperty(WebRenderUserDataProperty::Key())) { + uint32_t key = static_cast(DisplayItemType::TYPE_XUL_IMAGE); + RefPtr data = + GetWebRenderUserData(this, key); + if (data) { + data->SetInvalid(true); + } + SchedulePaint(); + return NS_OK; + } + InvalidateLayer(DisplayItemType::TYPE_XUL_IMAGE); return NS_OK; diff --git a/media/libvorbis/aarch64-win.patch b/media/libvorbis/aarch64-win.patch new file mode 100644 index 000000000000..6459950a995b --- /dev/null +++ b/media/libvorbis/aarch64-win.patch @@ -0,0 +1,13 @@ +diff --git a/lib/os.h b/lib/os.h +index 416a401..44d54fe 100644 +--- a/lib/os.h ++++ b/lib/os.h +@@ -147,7 +147,7 @@ static __inline void vorbis_fpu_restore(vorbis_fpu_control fpu){ + + /* Optimized code path for x86_64 builds. Uses SSE2 intrinsics. This can be + done safely because all x86_64 CPUs supports SSE2. */ +-#if (defined(_MSC_VER) && defined(_WIN64)) || (defined(__GNUC__) && defined (__x86_64__)) ++#if (defined(_MSC_VER) && defined(_M_X64)) || (defined(__GNUC__) && defined (__x86_64__)) + # define VORBIS_FPU_CONTROL + + typedef ogg_int16_t vorbis_fpu_control; diff --git a/media/libvorbis/lib/os.h b/media/libvorbis/lib/os.h index 416a401dd1b9..44d54feafd4f 100644 --- a/media/libvorbis/lib/os.h +++ b/media/libvorbis/lib/os.h @@ -147,7 +147,7 @@ static __inline void vorbis_fpu_restore(vorbis_fpu_control fpu){ /* Optimized code path for x86_64 builds. Uses SSE2 intrinsics. This can be done safely because all x86_64 CPUs supports SSE2. */ -#if (defined(_MSC_VER) && defined(_WIN64)) || (defined(__GNUC__) && defined (__x86_64__)) +#if (defined(_MSC_VER) && defined(_M_X64)) || (defined(__GNUC__) && defined (__x86_64__)) # define VORBIS_FPU_CONTROL typedef ogg_int16_t vorbis_fpu_control; diff --git a/media/libvorbis/update.sh b/media/libvorbis/update.sh index 7423993cbd51..7c9b6f6ebbf8 100755 --- a/media/libvorbis/update.sh +++ b/media/libvorbis/update.sh @@ -84,4 +84,4 @@ cp $1/lib/books/floor/floor_books.h ./lib/books/floor/ cp $1/lib/books/uncoupled/res_books_uncoupled.h ./lib/books/uncoupled/ # Add any patches against upstream here. -# ...nothing to apply... +patch -p1 < ./aarch64-win.patch diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/NavigationDelegateTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/NavigationDelegateTest.kt index 8285da59592f..3fdb892a878e 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/NavigationDelegateTest.kt +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/NavigationDelegateTest.kt @@ -201,6 +201,37 @@ class NavigationDelegateTest : BaseSessionTest() { }) } + @Test fun redirectLoad() { + val redirectUri = if (sessionRule.env.isAutomation) { + "http://example.org/tests/robocop/robocop_blank_02.html" + } else { + "http://jigsaw.w3.org/HTTP/300/Overview.html" + } + val uri = if (sessionRule.env.isAutomation) { + "http://example.org/tests/robocop/simple_redirect.sjs?$redirectUri" + } else { + "http://jigsaw.w3.org/HTTP/300/301.html" + } + + sessionRule.session.loadUri(uri) + sessionRule.waitForPageStop() + + sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationDelegate { + @AssertCalled(count = 2, order = [1, 2]) + override fun onLoadRequest(session: GeckoSession, uri: String, + where: Int, flags: Int): GeckoResult? { + assertThat("Session should not be null", session, notNullValue()) + assertThat("URI should not be null", uri, notNullValue()) + assertThat("URL should match", uri, + equalTo(forEachCall(uri, redirectUri))) + assertThat("Where should not be null", where, notNullValue()) + assertThat("Where should match", where, + equalTo(GeckoSession.NavigationDelegate.TARGET_WINDOW_CURRENT)) + return null + } + }) + } + @WithDevToolsAPI @Test fun desktopMode() { sessionRule.session.loadUri("https://example.com") diff --git a/netwerk/base/SimpleChannelParent.cpp b/netwerk/base/SimpleChannelParent.cpp index 00098959dbfb..81b0ee084fac 100644 --- a/netwerk/base/SimpleChannelParent.cpp +++ b/netwerk/base/SimpleChannelParent.cpp @@ -38,6 +38,13 @@ SimpleChannelParent::NotifyTrackingProtectionDisabled() return NS_OK; } +NS_IMETHODIMP +SimpleChannelParent::NotifyTrackingCookieBlocked() +{ + // Nothing to do. + return NS_OK; +} + NS_IMETHODIMP SimpleChannelParent::NotifyTrackingResource(bool aIsThirdParty) { diff --git a/netwerk/base/nsIParentChannel.idl b/netwerk/base/nsIParentChannel.idl index 4d00ae7fcc49..ec2ba3530a70 100644 --- a/netwerk/base/nsIParentChannel.idl +++ b/netwerk/base/nsIParentChannel.idl @@ -34,6 +34,12 @@ interface nsIParentChannel : nsIStreamListener */ [noscript] void notifyTrackingProtectionDisabled(); + /** + * Called to notify the HttpChannelChild that cookie has been blocked for + * this load. + */ + [noscript] void notifyTrackingCookieBlocked(); + /** * Called to set matched information when URL matches SafeBrowsing list. * @param aList diff --git a/netwerk/cookie/nsCookieService.cpp b/netwerk/cookie/nsCookieService.cpp index d5ec6f7952c8..7aa7f69cdc18 100644 --- a/netwerk/cookie/nsCookieService.cpp +++ b/netwerk/cookie/nsCookieService.cpp @@ -2234,7 +2234,7 @@ nsCookieService::SetCookieStringInternal(nsIURI *aHostURI, // (but not if there was an error) switch (cookieStatus) { case STATUS_REJECTED: - NotifyRejected(aHostURI); + NotifyRejected(aHostURI, aChannel); if (aIsForeign) { NotifyThirdParty(aHostURI, false, aChannel); } @@ -2264,12 +2264,14 @@ nsCookieService::SetCookieStringInternal(nsIURI *aHostURI, // notify observers that a cookie was rejected due to the users' prefs. void -nsCookieService::NotifyRejected(nsIURI *aHostURI) +nsCookieService::NotifyRejected(nsIURI *aHostURI, nsIChannel* aChannel) { nsCOMPtr os = mozilla::services::GetObserverService(); if (os) { os->NotifyObservers(aHostURI, "cookie-rejected", nullptr); } + + AntiTrackingCommon::NotifyRejection(aChannel); } // notify observers that a third-party cookie was accepted/rejected @@ -3608,7 +3610,7 @@ nsCookieService::SetCookieInternal(nsIURI *aHostURI, &permission); if (!permission) { COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader, "cookie rejected by permission manager"); - NotifyRejected(aHostURI); + NotifyRejected(aHostURI, aChannel); return newCookie; } diff --git a/netwerk/cookie/nsCookieService.h b/netwerk/cookie/nsCookieService.h index dd4b70d9fd3d..863f641b4e54 100644 --- a/netwerk/cookie/nsCookieService.h +++ b/netwerk/cookie/nsCookieService.h @@ -319,7 +319,7 @@ class nsCookieService final : public nsICookieService bool FindSecureCookie(const nsCookieKey& aKey, nsCookie* aCookie); int64_t FindStaleCookie(nsCookieEntry *aEntry, int64_t aCurrentTime, nsIURI* aSource, const mozilla::Maybe &aIsSecure, nsListIter &aIter); void TelemetryForEvictingStaleCookie(nsCookie* aEvicted, int64_t oldestCookieTime); - void NotifyRejected(nsIURI *aHostURI); + void NotifyRejected(nsIURI *aHostURI, nsIChannel* aChannel); void NotifyThirdParty(nsIURI *aHostURI, bool aAccepted, nsIChannel *aChannel); void NotifyChanged(nsISupports *aSubject, const char16_t *aData, bool aOldCookieIsSession = false, bool aFromHttp = false); void NotifyPurged(nsICookie2* aCookie); diff --git a/netwerk/protocol/data/DataChannelParent.cpp b/netwerk/protocol/data/DataChannelParent.cpp index 0d1789951bf4..757caf5b9687 100644 --- a/netwerk/protocol/data/DataChannelParent.cpp +++ b/netwerk/protocol/data/DataChannelParent.cpp @@ -38,6 +38,13 @@ DataChannelParent::NotifyTrackingProtectionDisabled() return NS_OK; } +NS_IMETHODIMP +DataChannelParent::NotifyTrackingCookieBlocked() +{ + // Nothing to do. + return NS_OK; +} + NS_IMETHODIMP DataChannelParent::NotifyTrackingResource(bool aIsThirdParty) { diff --git a/netwerk/protocol/file/FileChannelParent.cpp b/netwerk/protocol/file/FileChannelParent.cpp index 9bb699ae66f5..2a4576c5e6ec 100644 --- a/netwerk/protocol/file/FileChannelParent.cpp +++ b/netwerk/protocol/file/FileChannelParent.cpp @@ -38,6 +38,13 @@ FileChannelParent::NotifyTrackingProtectionDisabled() return NS_OK; } +NS_IMETHODIMP +FileChannelParent::NotifyTrackingCookieBlocked() +{ + // Nothing to do. + return NS_OK; +} + NS_IMETHODIMP FileChannelParent::NotifyTrackingResource(bool aIsThirdParty) { diff --git a/netwerk/protocol/ftp/FTPChannelParent.cpp b/netwerk/protocol/ftp/FTPChannelParent.cpp index 438b9f3de89f..1d7f02504d10 100644 --- a/netwerk/protocol/ftp/FTPChannelParent.cpp +++ b/netwerk/protocol/ftp/FTPChannelParent.cpp @@ -576,6 +576,13 @@ FTPChannelParent::NotifyTrackingProtectionDisabled() return NS_OK; } +NS_IMETHODIMP +FTPChannelParent::NotifyTrackingCookieBlocked() +{ + // One day, this should probably be filled in. + return NS_OK; +} + NS_IMETHODIMP FTPChannelParent::NotifyTrackingResource(bool aIsThirdParty) { diff --git a/netwerk/protocol/http/HttpBackgroundChannelChild.cpp b/netwerk/protocol/http/HttpBackgroundChannelChild.cpp index ce6484e4f4e8..4068809e80c8 100644 --- a/netwerk/protocol/http/HttpBackgroundChannelChild.cpp +++ b/netwerk/protocol/http/HttpBackgroundChannelChild.cpp @@ -347,6 +347,21 @@ HttpBackgroundChannelChild::RecvNotifyTrackingProtectionDisabled() return IPC_OK(); } +IPCResult +HttpBackgroundChannelChild::RecvNotifyTrackingCookieBlocked() +{ + LOG(("HttpBackgroundChannelChild::RecvNotifyTrackingCookieBlocked [this=%p]\n", this)); + MOZ_ASSERT(OnSocketThread()); + + if (NS_WARN_IF(!mChannelChild)) { + return IPC_OK(); + } + + mChannelChild->ProcessNotifyTrackingCookieBlocked(); + + return IPC_OK(); +} + IPCResult HttpBackgroundChannelChild::RecvNotifyTrackingResource(const bool& aIsThirdParty) { diff --git a/netwerk/protocol/http/HttpBackgroundChannelChild.h b/netwerk/protocol/http/HttpBackgroundChannelChild.h index 43a7adb2aba6..dad79ee4f3c2 100644 --- a/netwerk/protocol/http/HttpBackgroundChannelChild.h +++ b/netwerk/protocol/http/HttpBackgroundChannelChild.h @@ -65,6 +65,8 @@ protected: IPCResult RecvNotifyTrackingProtectionDisabled() override; + IPCResult RecvNotifyTrackingCookieBlocked() override; + IPCResult RecvNotifyTrackingResource(const bool& aIsThirdParty) override; IPCResult RecvSetClassifierMatchedInfo(const ClassifierInfo& info) override; diff --git a/netwerk/protocol/http/HttpBackgroundChannelParent.cpp b/netwerk/protocol/http/HttpBackgroundChannelParent.cpp index 7196c92e36f6..019acf38396d 100644 --- a/netwerk/protocol/http/HttpBackgroundChannelParent.cpp +++ b/netwerk/protocol/http/HttpBackgroundChannelParent.cpp @@ -379,6 +379,33 @@ HttpBackgroundChannelParent::OnNotifyTrackingProtectionDisabled() return SendNotifyTrackingProtectionDisabled(); } +bool +HttpBackgroundChannelParent::OnNotifyTrackingCookieBlocked() +{ + LOG(("HttpBackgroundChannelParent::OnNotifyTrackingCookieBlocked [this=%p]\n", this)); + AssertIsInMainProcess(); + + if (NS_WARN_IF(!mIPCOpened)) { + return false; + } + + if (!IsOnBackgroundThread()) { + MutexAutoLock lock(mBgThreadMutex); + nsresult rv = mBackgroundThread->Dispatch( + NewRunnableMethod( + "net::HttpBackgroundChannelParent::OnNotifyTrackingCookieBlocked", + this, + &HttpBackgroundChannelParent::OnNotifyTrackingCookieBlocked), + NS_DISPATCH_NORMAL); + + MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv)); + + return NS_SUCCEEDED(rv); + } + + return SendNotifyTrackingCookieBlocked(); +} + bool HttpBackgroundChannelParent::OnNotifyTrackingResource(bool aIsThirdParty) { diff --git a/netwerk/protocol/http/HttpBackgroundChannelParent.h b/netwerk/protocol/http/HttpBackgroundChannelParent.h index 5ddab6f9b51c..179601d92174 100644 --- a/netwerk/protocol/http/HttpBackgroundChannelParent.h +++ b/netwerk/protocol/http/HttpBackgroundChannelParent.h @@ -69,6 +69,9 @@ public: // To send NotifyTrackingProtectionDisabled message over background channel. bool OnNotifyTrackingProtectionDisabled(); + // To send NotifyTrackingCookieBlocked message over background channel. + bool OnNotifyTrackingCookieBlocked(); + // To send NotifyTrackingResource message over background channel. bool OnNotifyTrackingResource(bool aIsThirdParty); diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp index d84dd39f0111..7d5b8adacc18 100644 --- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -10,6 +10,7 @@ #include "nsHttp.h" #include "nsICacheEntry.h" +#include "mozilla/AntiTrackingCommon.h" #include "mozilla/Unused.h" #include "mozilla/dom/ContentChild.h" #include "mozilla/dom/DocGroup.h" @@ -2039,6 +2040,23 @@ HttpChannelChild::ProcessNotifyTrackingProtectionDisabled() NS_DISPATCH_NORMAL); } +void +HttpChannelChild::ProcessNotifyTrackingCookieBlocked() +{ + LOG(("HttpChannelChild::ProcessNotifyTrackingCookieBlocked [this=%p]\n", this)); + MOZ_ASSERT(OnSocketThread()); + + RefPtr self = this; + nsCOMPtr neckoTarget = GetNeckoTarget(); + neckoTarget->Dispatch( + NS_NewRunnableFunction( + "nsChannelClassifier::NotifyTrackingCookieBlocked", + [self]() { + AntiTrackingCommon::NotifyRejection(self); + }), + NS_DISPATCH_NORMAL); +} + void HttpChannelChild::ProcessNotifyTrackingResource(bool aIsThirdParty) { diff --git a/netwerk/protocol/http/HttpChannelChild.h b/netwerk/protocol/http/HttpChannelChild.h index 8f6bb4179238..f3b8ae0a1708 100644 --- a/netwerk/protocol/http/HttpChannelChild.h +++ b/netwerk/protocol/http/HttpChannelChild.h @@ -253,6 +253,7 @@ private: void ProcessFlushedForDiversion(); void ProcessDivertMessages(); void ProcessNotifyTrackingProtectionDisabled(); + void ProcessNotifyTrackingCookieBlocked(); void ProcessNotifyTrackingResource(bool aIsThirdParty); void ProcessSetClassifierMatchedInfo(const nsCString& aList, const nsCString& aProvider, diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp index 21b2ace5dff2..4c34216015d2 100644 --- a/netwerk/protocol/http/HttpChannelParent.cpp +++ b/netwerk/protocol/http/HttpChannelParent.cpp @@ -1805,7 +1805,18 @@ HttpChannelParent::NotifyTrackingProtectionDisabled() LOG(("HttpChannelParent::NotifyTrackingProtectionDisabled [this=%p]\n", this)); if (!mIPCClosed) { MOZ_ASSERT(mBgParent); - Unused << mBgParent->OnNotifyTrackingProtectionDisabled(); + Unused << NS_WARN_IF(!mBgParent->OnNotifyTrackingProtectionDisabled()); + } + return NS_OK; +} + +NS_IMETHODIMP +HttpChannelParent::NotifyTrackingCookieBlocked() +{ + LOG(("HttpChannelParent::NotifyTrackingCookieBlocked [this=%p]\n", this)); + if (!mIPCClosed) { + MOZ_ASSERT(mBgParent); + Unused << NS_WARN_IF(!mBgParent->OnNotifyTrackingCookieBlocked()); } return NS_OK; } diff --git a/netwerk/protocol/http/PHttpBackgroundChannel.ipdl b/netwerk/protocol/http/PHttpBackgroundChannel.ipdl index 1a9f3d40fb31..cbddd2bb3f8f 100644 --- a/netwerk/protocol/http/PHttpBackgroundChannel.ipdl +++ b/netwerk/protocol/http/PHttpBackgroundChannel.ipdl @@ -56,6 +56,9 @@ child: // Tell the child that tracking protection was disabled for this load. async NotifyTrackingProtectionDisabled(); + // Tell the child that tracking cookies are blocked for this load. + async NotifyTrackingCookieBlocked(); + // Tell the child that the resource being loaded is on the tracking // protection list. async NotifyTrackingResource(bool aIsThirdParty); diff --git a/testing/marionette/driver.js b/testing/marionette/driver.js index 7cdbaa739f8b..2b079588e959 100644 --- a/testing/marionette/driver.js +++ b/testing/marionette/driver.js @@ -3143,7 +3143,7 @@ GeckoDriver.prototype.dismissDialog = async function() { await new Promise(resolve => { win.addEventListener("DOMModalDialogClosed", whenIdle(win, () => { - this.dialog = null; + this.dialog = modal.findModalDialogs(this.curBrowser); resolve(); }), {once: true}); @@ -3162,7 +3162,7 @@ GeckoDriver.prototype.acceptDialog = async function() { await new Promise(resolve => { win.addEventListener("DOMModalDialogClosed", whenIdle(win, () => { - this.dialog = null; + this.dialog = modal.findModalDialogs(this.curBrowser); resolve(); }), {once: true}); diff --git a/testing/marionette/harness/marionette_harness/tests/unit/test_modal_dialogs.py b/testing/marionette/harness/marionette_harness/tests/unit/test_modal_dialogs.py index 429fb16e69fe..4c71384185bd 100644 --- a/testing/marionette/harness/marionette_harness/tests/unit/test_modal_dialogs.py +++ b/testing/marionette/harness/marionette_harness/tests/unit/test_modal_dialogs.py @@ -1,7 +1,3 @@ -# 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/. - from __future__ import absolute_import from marionette_driver.by import By @@ -10,7 +6,7 @@ from marionette_driver import errors from marionette_driver.marionette import Alert from marionette_driver.wait import Wait -from marionette_harness import MarionetteTestCase, WindowManagerMixin +from marionette_harness import MarionetteTestCase, parameterized, WindowManagerMixin class BaseAlertTestCase(WindowManagerMixin, MarionetteTestCase): @@ -27,10 +23,6 @@ class BaseAlertTestCase(WindowManagerMixin, MarionetteTestCase): Wait(self.marionette, timeout=timeout).until( lambda _: self.alert_present) - def wait_for_alert_closed(self, timeout=None): - Wait(self.marionette, timeout=timeout).until( - lambda _: not self.alert_present) - class TestTabModalAlerts(BaseAlertTestCase): @@ -43,13 +35,12 @@ class TestTabModalAlerts(BaseAlertTestCase): self.marionette.navigate(self.test_page) def tearDown(self): - # Ensure to close a possible remaining tab modal dialog + # Ensure to close all possible remaining tab modal dialogs try: - alert = self.marionette.switch_to_alert() - alert.dismiss() - - self.wait_for_alert_closed() - except: + while True: + alert = self.marionette.switch_to_alert() + alert.dismiss() + except errors.NoAlertPresentException: pass super(TestTabModalAlerts, self).tearDown() @@ -60,50 +51,6 @@ class TestTabModalAlerts(BaseAlertTestCase): with self.assertRaises(errors.NoAlertPresentException): Alert(self.marionette).dismiss() - def test_alert_accept(self): - self.marionette.find_element(By.ID, "tab-modal-alert").click() - self.wait_for_alert() - alert = self.marionette.switch_to_alert() - alert.accept() - - def test_alert_dismiss(self): - self.marionette.find_element(By.ID, "tab-modal-alert").click() - self.wait_for_alert() - alert = self.marionette.switch_to_alert() - alert.dismiss() - - def test_confirm_accept(self): - self.marionette.find_element(By.ID, "tab-modal-confirm").click() - self.wait_for_alert() - alert = self.marionette.switch_to_alert() - alert.accept() - self.wait_for_condition( - lambda mn: mn.find_element(By.ID, "confirm-result").text == "true") - - def test_confirm_dismiss(self): - self.marionette.find_element(By.ID, "tab-modal-confirm").click() - self.wait_for_alert() - alert = self.marionette.switch_to_alert() - alert.dismiss() - self.wait_for_condition( - lambda mn: mn.find_element(By.ID, "confirm-result").text == "false") - - def test_prompt_accept(self): - self.marionette.find_element(By.ID, "tab-modal-prompt").click() - self.wait_for_alert() - alert = self.marionette.switch_to_alert() - alert.accept() - self.wait_for_condition( - lambda mn: mn.find_element(By.ID, "prompt-result").text == "") - - def test_prompt_dismiss(self): - self.marionette.find_element(By.ID, "tab-modal-prompt").click() - self.wait_for_alert() - alert = self.marionette.switch_to_alert() - alert.dismiss() - self.wait_for_condition( - lambda mn: mn.find_element(By.ID, "prompt-result").text == "null") - def test_alert_opened_before_session_starts(self): self.marionette.find_element(By.ID, "tab-modal-alert").click() self.wait_for_alert() @@ -115,40 +62,45 @@ class TestTabModalAlerts(BaseAlertTestCase): alert = self.marionette.switch_to_alert() alert.dismiss() - def test_alert_text(self): + @parameterized("alert", "alert", "undefined") + @parameterized("confirm", "confirm", "true") + @parameterized("prompt", "prompt", "") + def test_accept(self, value, result): + self.marionette.find_element(By.ID, "tab-modal-{}".format(value)).click() + self.wait_for_alert() + alert = self.marionette.switch_to_alert() + alert.accept() + self.assertEqual(self.marionette.find_element(By.ID, "text").text, result) + + @parameterized("alert", "alert", "undefined") + @parameterized("confirm", "confirm", "false") + @parameterized("prompt", "prompt", "null") + def test_dismiss(self, value, result): + self.marionette.find_element(By.ID, "tab-modal-{}".format(value)).click() + self.wait_for_alert() + alert = self.marionette.switch_to_alert() + alert.dismiss() + self.assertEqual(self.marionette.find_element(By.ID, "text").text, result) + + @parameterized("alert", "alert", "Marionette alert") + @parameterized("confirm", "confirm", "Marionette confirm") + @parameterized("prompt", "prompt", "Marionette prompt") + def test_text(self, value, text): with self.assertRaises(errors.NoAlertPresentException): alert = self.marionette.switch_to_alert() alert.text - self.marionette.find_element(By.ID, "tab-modal-alert").click() + self.marionette.find_element(By.ID, "tab-modal-{}".format(value)).click() self.wait_for_alert() alert = self.marionette.switch_to_alert() - self.assertEqual(alert.text, "Marionette alert") + self.assertEqual(alert.text, text) alert.accept() - def test_prompt_text(self): - with self.assertRaises(errors.NoAlertPresentException): - alert = self.marionette.switch_to_alert() - alert.text - self.marionette.find_element(By.ID, "tab-modal-prompt").click() - self.wait_for_alert() - alert = self.marionette.switch_to_alert() - self.assertEqual(alert.text, "Marionette prompt") - alert.accept() - - def test_confirm_text(self): - with self.assertRaises(errors.NoAlertPresentException): - alert = self.marionette.switch_to_alert() - alert.text - self.marionette.find_element(By.ID, "tab-modal-confirm").click() - self.wait_for_alert() - alert = self.marionette.switch_to_alert() - self.assertEqual(alert.text, "Marionette confirm") - alert.accept() - - def test_set_text_throws(self): + @parameterized("alert", "alert") + @parameterized("confirm", "confirm") + def test_set_text_throws(self, value): with self.assertRaises(errors.NoAlertPresentException): Alert(self.marionette).send_keys("Foo") - self.marionette.find_element(By.ID, "tab-modal-alert").click() + self.marionette.find_element(By.ID, "tab-modal-{}".format(value)).click() self.wait_for_alert() alert = self.marionette.switch_to_alert() with self.assertRaises(errors.ElementNotInteractableException): @@ -159,10 +111,9 @@ class TestTabModalAlerts(BaseAlertTestCase): self.marionette.find_element(By.ID, "tab-modal-prompt").click() self.wait_for_alert() alert = self.marionette.switch_to_alert() - alert.send_keys("Some text!") + alert.send_keys("Foo bar") alert.accept() - self.wait_for_condition( - lambda mn: mn.find_element(By.ID, "prompt-result").text == "Some text!") + self.assertEqual(self.marionette.find_element(By.ID, "text").text, "Foo bar") def test_set_text_dismiss(self): self.marionette.find_element(By.ID, "tab-modal-prompt").click() @@ -170,35 +121,51 @@ class TestTabModalAlerts(BaseAlertTestCase): alert = self.marionette.switch_to_alert() alert.send_keys("Some text!") alert.dismiss() - self.wait_for_condition( - lambda mn: mn.find_element(By.ID, "prompt-result").text == "null") + self.assertEqual(self.marionette.find_element(By.ID, "text").text, "null") def test_unrelated_command_when_alert_present(self): self.marionette.find_element(By.ID, "tab-modal-alert").click() self.wait_for_alert() with self.assertRaises(errors.UnexpectedAlertOpen): - self.marionette.find_element(By.ID, "click-result") + self.marionette.find_element(By.ID, "text") def test_modal_is_dismissed_after_unexpected_alert(self): self.marionette.find_element(By.ID, "tab-modal-alert").click() self.wait_for_alert() with self.assertRaises(errors.UnexpectedAlertOpen): - self.marionette.find_element(By.ID, "click-result") + self.marionette.find_element(By.ID, "text") assert not self.alert_present + def test_handle_two_modal_dialogs(self): + self.marionette.find_element(By.ID, "open-two-dialogs").click() + + self.wait_for_alert() + alert1 = self.marionette.switch_to_alert() + alert1.send_keys("foo") + alert1.accept() + + alert2 = self.marionette.switch_to_alert() + alert2.send_keys("bar") + alert2.accept() + + self.assertEqual(self.marionette.find_element(By.ID, "text1").text, "foo") + self.assertEqual(self.marionette.find_element(By.ID, "text2").text, "bar") + class TestModalAlerts(BaseAlertTestCase): def setUp(self): super(TestModalAlerts, self).setUp() - self.marionette.set_pref("network.auth.non-web-content-triggered-resources-http-auth-allow", - True) + self.marionette.set_pref( + "network.auth.non-web-content-triggered-resources-http-auth-allow", + True) def tearDown(self): # Ensure to close a possible remaining modal dialog self.close_all_windows() - self.marionette.clear_pref("network.auth.non-web-content-triggered-resources-http-auth-allow") + self.marionette.clear_pref( + "network.auth.non-web-content-triggered-resources-http-auth-allow") super(TestModalAlerts, self).tearDown() @@ -209,8 +176,6 @@ class TestModalAlerts(BaseAlertTestCase): alert = self.marionette.switch_to_alert() alert.dismiss() - self.wait_for_alert_closed() - status = Wait(self.marionette, timeout=self.marionette.timeout.page_load).until( element_present(By.ID, "status") ) @@ -226,5 +191,3 @@ class TestModalAlerts(BaseAlertTestCase): alert = self.marionette.switch_to_alert() alert.dismiss() - - self.wait_for_alert_closed() diff --git a/testing/marionette/harness/marionette_harness/www/test_tab_modal_dialogs.html b/testing/marionette/harness/marionette_harness/www/test_tab_modal_dialogs.html index e31364ec20df..155a36d70f17 100644 --- a/testing/marionette/harness/marionette_harness/www/test_tab_modal_dialogs.html +++ b/testing/marionette/harness/marionette_harness/www/test_tab_modal_dialogs.html @@ -7,28 +7,37 @@ Dialog Test - Open an alert dialog. - Open a confirm dialog. - Open a prompt dialog. - Make text appear. -
-
-
+ Open an alert dialog. + Open a confirm dialog. + Open a prompt dialog. + Open two prompts. + Make text appear. + +
+
+
diff --git a/toolkit/components/antitracking/AntiTrackingCommon.cpp b/toolkit/components/antitracking/AntiTrackingCommon.cpp index 5ff71aae5632..1a0c6dbd6b8a 100644 --- a/toolkit/components/antitracking/AntiTrackingCommon.cpp +++ b/toolkit/components/antitracking/AntiTrackingCommon.cpp @@ -19,10 +19,13 @@ #include "nsICookieService.h" #include "nsIHttpChannelInternal.h" #include "nsIIOService.h" +#include "nsIParentChannel.h" #include "nsIPermissionManager.h" #include "nsIPrincipal.h" #include "nsIURI.h" #include "nsIURL.h" +#include "nsIWebProgressListener.h" +#include "nsNetUtil.h" #include "nsPIDOMWindow.h" #include "nsScriptSecurityManager.h" #include "prtime.h" @@ -833,3 +836,68 @@ AntiTrackingCommon::IsOnContentBlockingAllowList(nsIURI* aTopWinURI, return NS_OK; } + +/* static */ void +AntiTrackingCommon::NotifyRejection(nsIChannel* aChannel) +{ + nsCOMPtr httpChannel = do_QueryInterface(aChannel); + if (!httpChannel) { + return; + } + + // Can be called in EITHER the parent or child process. + nsCOMPtr parentChannel; + NS_QueryNotificationCallbacks(aChannel, parentChannel); + if (parentChannel) { + // This channel is a parent-process proxy for a child process request. + // Tell the child process channel to do this instead. + parentChannel->NotifyTrackingCookieBlocked(); + return; + } + + nsCOMPtr thirdPartyUtil = services::GetThirdPartyUtil(); + if (!thirdPartyUtil) { + return; + } + + nsCOMPtr win; + nsresult rv = thirdPartyUtil->GetTopWindowForChannel(httpChannel, + getter_AddRefs(win)); + NS_ENSURE_SUCCESS_VOID(rv); + + nsCOMPtr pwin = nsPIDOMWindowOuter::From(win); + if (!pwin) { + return; + } + + pwin->NotifyContentBlockingState( + nsIWebProgressListener::STATE_BLOCKED_TRACKING_COOKIES, httpChannel); +} + +/* static */ void +AntiTrackingCommon::NotifyRejection(nsPIDOMWindowInner* aWindow) +{ + MOZ_ASSERT(aWindow); + + nsIDocument* document = aWindow->GetExtantDoc(); + if (!document) { + return; + } + + nsCOMPtr httpChannel = + do_QueryInterface(document->GetChannel()); + if (!httpChannel) { + return; + } + + nsCOMPtr pwin; + auto* outer = nsGlobalWindowOuter::Cast(aWindow->GetOuterWindow()); + if (outer) { + pwin = outer->GetTopOuter(); + } + + if (pwin) { + pwin->NotifyContentBlockingState( + nsIWebProgressListener::STATE_BLOCKED_TRACKING_COOKIES, httpChannel); + } +} diff --git a/toolkit/components/antitracking/AntiTrackingCommon.h b/toolkit/components/antitracking/AntiTrackingCommon.h index 4733589ffdf9..dbb6d37fae20 100644 --- a/toolkit/components/antitracking/AntiTrackingCommon.h +++ b/toolkit/components/antitracking/AntiTrackingCommon.h @@ -11,6 +11,7 @@ #include "mozilla/MozPromise.h" #include "mozilla/RefPtr.h" +class nsIChannel; class nsIHttpChannel; class nsIPrincipal; class nsIURI; @@ -88,6 +89,14 @@ public: static nsresult IsOnContentBlockingAllowList(nsIURI* aTopWinURI, bool& aIsAllowListed); + // This method can be called on the parent process or on the content process. + // The notification is propagated to the child channel if aChannel is a parent + // channel proxy. + static void + NotifyRejection(nsIChannel* aChannel); + + static void + NotifyRejection(nsPIDOMWindowInner* aWindow); }; } // namespace mozilla diff --git a/toolkit/components/antitracking/test/browser/browser_blockingStorage.js b/toolkit/components/antitracking/test/browser/browser_blockingStorage.js index 14cded2cc205..0663ab932954 100644 --- a/toolkit/components/antitracking/test/browser/browser_blockingStorage.js +++ b/toolkit/components/antitracking/test/browser/browser_blockingStorage.js @@ -31,4 +31,8 @@ AntiTracking.runTest("sessionStorage", await new Promise(resolve => { Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => resolve()); }); - }); + }, + [], + true, + true, + false); diff --git a/toolkit/components/antitracking/test/browser/head.js b/toolkit/components/antitracking/test/browser/head.js index d594ce53cccd..710669a9de8d 100644 --- a/toolkit/components/antitracking/test/browser/head.js +++ b/toolkit/components/antitracking/test/browser/head.js @@ -21,9 +21,17 @@ var gFeatures = undefined; let {UrlClassifierTestUtils} = ChromeUtils.import("resource://testing-common/UrlClassifierTestUtils.jsm", {}); this.AntiTracking = { - runTest(name, callbackTracking, callbackNonTracking, cleanupFunction, extraPrefs, windowOpenTest = true, userInteractionTest = true) { + runTest(name, callbackTracking, callbackNonTracking, cleanupFunction, extraPrefs, windowOpenTest = true, userInteractionTest = true, expectedBlockingNotifications = true) { // Here we want to test that a 3rd party context is simply blocked. - this._createTask(name, true, true, false, callbackTracking, extraPrefs); + this._createTask({ + name, + cookieBehavior: BEHAVIOR_REJECT_TRACKER, + blockingByContentBlocking: true, + allowList: false, + callback: callbackTracking, + extraPrefs, + expectedBlockingNotifications, + }); this._createCleanupTask(cleanupFunction); if (callbackNonTracking) { @@ -59,35 +67,104 @@ this.AntiTracking = { // * If both of these prefs cause it to not be blocked. // * If the top-level page is on the content blocking allow list. // All of these cases are tested here. - this._createTask(name, BEHAVIOR_ACCEPT, true, false, callbackNonTracking); + this._createTask({ + name, + cookieBehavior: BEHAVIOR_ACCEPT, + blockingByContentBlocking: true, + allowList: false, + callback: callbackNonTracking, + extraPrefs: [], + expectedBlockingNotifications: false, + }); this._createCleanupTask(cleanupFunction); - this._createTask(name, BEHAVIOR_REJECT_FOREIGN, false, false, callbackNonTracking); + this._createTask({ + name, + cookieBehavior: BEHAVIOR_REJECT_FOREIGN, + blockingByContentBlocking: false, + allowList: false, + callback: callbackNonTracking, + extraPrefs: [], + expectedBlockingNotifications: false, + }); this._createCleanupTask(cleanupFunction); - this._createTask(name, BEHAVIOR_REJECT_TRACKER, false, false, callbackNonTracking); + this._createTask({ + name, + cookieBehavior: BEHAVIOR_REJECT_TRACKER, + blockingByContentBlocking: false, + allowList: false, + callback: callbackNonTracking, + extraPrefs: [], + expectedBlockingNotifications: false, + }); this._createCleanupTask(cleanupFunction); - this._createTask(name, BEHAVIOR_REJECT_FOREIGN, false, true, callbackNonTracking); + this._createTask({ + name, + cookieBehavior: BEHAVIOR_REJECT_FOREIGN, + blockingByContentBlocking: false, + allowList: true, + callback: callbackNonTracking, + extraPrefs: [], + expectedBlockingNotifications: false, + }); this._createCleanupTask(cleanupFunction); - this._createTask(name, BEHAVIOR_REJECT_TRACKER, false, true, callbackNonTracking); + this._createTask({ + name, + cookieBehavior: BEHAVIOR_REJECT_TRACKER, + blockingByContentBlocking: false, + allowList: true, + callback: callbackNonTracking, + extraPrefs: [], + expectedBlockingNotifications: false, + }); this._createCleanupTask(cleanupFunction); - this._createTask(name, BEHAVIOR_ACCEPT, false, false, callbackNonTracking); + this._createTask({ + name, + cookieBehavior: BEHAVIOR_ACCEPT, + blockingByContentBlocking: false, + allowList: false, + callback: callbackNonTracking, + extraPrefs: [], + expectedBlockingNotifications: false, + }); this._createCleanupTask(cleanupFunction); // Try testing using the allow list with both reject foreign and reject tracker cookie behaviors - this._createTask(name, BEHAVIOR_REJECT_FOREIGN, true, true, callbackNonTracking); + this._createTask({ + name, + cookieBehavior: BEHAVIOR_REJECT_FOREIGN, + blockingByContentBlocking: true, + allowList: true, + callback: callbackNonTracking, + extraPrefs: [], + expectedBlockingNotifications: false, + }); this._createCleanupTask(cleanupFunction); - this._createTask(name, BEHAVIOR_REJECT_TRACKER, true, true, callbackNonTracking); + this._createTask({ + name, + cookieBehavior: BEHAVIOR_REJECT_TRACKER, + blockingByContentBlocking: true, + allowList: true, + callback: callbackNonTracking, + extraPrefs: [], + expectedBlockingNotifications: false, + }); this._createCleanupTask(cleanupFunction); } else { - this._createTask(name, options.cookieBehavior, - options.blockingByContentBlocking, - options.blockingByAllowList, - callbackNonTracking); + this._createTask({ + name, + cookieBehavior: options.cookieBehavior, + blockingByContentBlocking: options.blockingByContentBlocking, + allowList: options.blockingByAllowList, + callback: callbackNonTracking, + extraPrefs: [], + expectedBlockingNotifications: false, + }); this._createCleanupTask(cleanupFunction); } @@ -125,14 +202,27 @@ this.AntiTracking = { await UrlClassifierTestUtils.addTestTrackers(); }, - _createTask(name, cookieBehavior, blockingByContentBlocking, - allowList, callback, extraPrefs) { + _createTask(options) { add_task(async function() { - info("Starting " + (cookieBehavior != BEHAVIOR_ACCEPT ? "blocking" : "non-blocking") + " cookieBehavior (" + cookieBehavior + ") and " + - (blockingByContentBlocking ? "blocking" : "non-blocking") + " contentBlocking with" + - (allowList ? "" : "out") + " allow list test " + name); + info("Starting " + (options.cookieBehavior != BEHAVIOR_ACCEPT ? "blocking" : "non-blocking") + " cookieBehavior (" + options.cookieBehavior + ") and " + + (options.blockingByContentBlocking ? "blocking" : "non-blocking") + " contentBlocking with" + + (options.allowList ? "" : "out") + " allow list test " + options.name); - await AntiTracking._setupTest(cookieBehavior, blockingByContentBlocking, extraPrefs); + requestLongerTimeout(2); + + await AntiTracking._setupTest(options.cookieBehavior, + options.blockingByContentBlocking, + options.extraPrefs); + + let cookieBlocked = 0; + let listener = { + onSecurityChange(webProgress, request, stateFlags, status) { + if (stateFlags & Ci.nsIWebProgressListener.STATE_BLOCKED_TRACKING_COOKIES) { + ++cookieBlocked; + } + } + }; + gBrowser.addProgressListener(listener); info("Creating a new tab"); let tab = BrowserTestUtils.addTab(gBrowser, TEST_TOP_PAGE); @@ -141,7 +231,7 @@ this.AntiTracking = { let browser = gBrowser.getBrowserForTab(tab); await BrowserTestUtils.browserLoaded(browser); - if (allowList) { + if (options.allowList) { info("Disabling content blocking for this page"); ContentBlocking.disableForCurrentPage(); @@ -152,7 +242,7 @@ this.AntiTracking = { info("Creating a 3rd party content"); await ContentTask.spawn(browser, { page: TEST_3RD_PARTY_PAGE, - callback: callback.toString() }, + callback: options.callback.toString() }, async function(obj) { await new content.Promise(resolve => { let ifr = content.document.createElement("iframe"); @@ -186,7 +276,7 @@ this.AntiTracking = { }); }); - if (allowList) { + if (options.allowList) { info("Enabling content blocking for this page"); ContentBlocking.enableForCurrentPage(); @@ -194,6 +284,10 @@ this.AntiTracking = { await BrowserTestUtils.browserLoaded(browser); } + gBrowser.removeProgressListener(listener); + + is(!!cookieBlocked, options.expectedBlockingNotifications, "Checking cookie blocking notifications"); + info("Removing the tab"); BrowserTestUtils.removeTab(tab); }); @@ -211,6 +305,9 @@ this.AntiTracking = { _createWindowOpenTask(name, blockingCallback, nonBlockingCallback, extraPrefs) { add_task(async function() { info("Starting window-open test " + name); + + requestLongerTimeout(2); + await AntiTracking._setupTest(BEHAVIOR_REJECT_TRACKER, true, extraPrefs); info("Creating a new tab"); @@ -272,6 +369,9 @@ this.AntiTracking = { _createUserInteractionTask(name, blockingCallback, nonBlockingCallback, extraPrefs) { add_task(async function() { info("Starting user-interaction test " + name); + + requestLongerTimeout(2); + await AntiTracking._setupTest(BEHAVIOR_REJECT_TRACKER, true, extraPrefs); info("Creating a new tab"); diff --git a/uriloader/exthandler/nsExternalProtocolHandler.cpp b/uriloader/exthandler/nsExternalProtocolHandler.cpp index b9830b6c4d6a..ae9d6d5ab57d 100644 --- a/uriloader/exthandler/nsExternalProtocolHandler.cpp +++ b/uriloader/exthandler/nsExternalProtocolHandler.cpp @@ -422,6 +422,12 @@ NS_IMETHODIMP nsExtProtocolChannel::NotifyTrackingProtectionDisabled() return NS_OK; } +NS_IMETHODIMP nsExtProtocolChannel::NotifyTrackingCookieBlocked() +{ + // nothing to do + return NS_OK; +} + NS_IMETHODIMP nsExtProtocolChannel::SetClassifierMatchedInfo(const nsACString& aList, const nsACString& aProvider, const nsACString& aFullHash)