diff --git a/browser/base/content/browser-sync.js b/browser/base/content/browser-sync.js index dd109a2a66e0..831e2dc28a36 100644 --- a/browser/base/content/browser-sync.js +++ b/browser/base/content/browser-sync.js @@ -1212,6 +1212,12 @@ var gSync = { if (confirm && !(await this._confirmDisconnect(disconnectAccount))) { return false; } + // Record telemetry. + await fxAccounts.telemetry.recordDisconnection( + disconnectAccount ? null : "sync", + "ui" + ); + await Weave.Service.promiseInitialized; await Weave.Service.startOver(); if (disconnectAccount) { diff --git a/browser/components/originattributes/test/browser/browser.ini b/browser/components/originattributes/test/browser/browser.ini index b24fa3032437..1c3ea556ba0c 100644 --- a/browser/components/originattributes/test/browser/browser.ini +++ b/browser/components/originattributes/test/browser/browser.ini @@ -81,6 +81,7 @@ skip-if = fission skip-if = (verify && debug && (os == 'win')) [browser_imageCacheIsolation.js] [browser_sharedworker.js] +skip-if = fission #Bug 1582318 [browser_httpauth.js] [browser_clientAuth.js] skip-if = verify diff --git a/browser/components/preferences/in-content/sync.js b/browser/components/preferences/in-content/sync.js index bee2fda9822d..02c5251ff3d2 100644 --- a/browser/components/preferences/in-content/sync.js +++ b/browser/components/preferences/in-content/sync.js @@ -302,7 +302,14 @@ var gSyncPane = { if (!isAlreadySyncing && event.detail.button == "accept") { // We weren't syncing but the user has accepted the dialog - so we // want to start! - Weave.Service.configure(); + fxAccounts.telemetry + .recordConnection(["sync"], "ui") + .then(() => { + return Weave.Service.configure(); + }) + .catch(err => { + console.error("Failed to enable sync", err); + }); } } ); diff --git a/devtools/client/inspector/compatibility/CompatibilityView.js b/devtools/client/inspector/compatibility/CompatibilityView.js index b79947c4f77c..41c8a9e59292 100644 --- a/devtools/client/inspector/compatibility/CompatibilityView.js +++ b/devtools/client/inspector/compatibility/CompatibilityView.js @@ -80,16 +80,18 @@ class CompatibilityView { ); } - _isVisible() { + _isAvailable() { return ( this.inspector && this.inspector.sidebar && - this.inspector.sidebar.getCurrentTabID() === "compatibilityview" + this.inspector.sidebar.getCurrentTabID() === "compatibilityview" && + this.inspector.selection && + this.inspector.selection.isConnected() ); } _onNewNode() { - if (!this._isVisible()) { + if (!this._isAvailable()) { return; } diff --git a/devtools/client/inspector/compatibility/actions/compatibility.js b/devtools/client/inspector/compatibility/actions/compatibility.js index 51192476a25f..3ed7764ccd09 100644 --- a/devtools/client/inspector/compatibility/actions/compatibility.js +++ b/devtools/client/inspector/compatibility/actions/compatibility.js @@ -5,19 +5,35 @@ "use strict"; const { - COMPATIBILITY_UPDATE_SELECTED_NODE, + COMPATIBILITY_UPDATE_SELECTED_NODE_START, + COMPATIBILITY_UPDATE_SELECTED_NODE_SUCCESS, + COMPATIBILITY_UPDATE_SELECTED_NODE_FAILURE, + COMPATIBILITY_UPDATE_SELECTED_NODE_COMPLETE, COMPATIBILITY_UPDATE_TARGET_BROWSERS, } = require("./index"); function updateSelectedNode(nodeFront) { return async ({ dispatch }) => { - const pageStyle = nodeFront.inspectorFront.pageStyle; - const styles = await pageStyle.getApplied(nodeFront, { skipPseudo: false }); - const declarationBlocks = styles - .map(({ rule }) => rule.declarations.filter(d => !d.commentOffsets)) - .filter(declarations => declarations.length); + dispatch({ type: COMPATIBILITY_UPDATE_SELECTED_NODE_START }); - dispatch({ type: COMPATIBILITY_UPDATE_SELECTED_NODE, declarationBlocks }); + try { + const pageStyle = nodeFront.inspectorFront.pageStyle; + const styles = await pageStyle.getApplied(nodeFront, { + skipPseudo: false, + }); + const declarationBlocks = styles + .map(({ rule }) => rule.declarations.filter(d => !d.commentOffsets)) + .filter(declarations => declarations.length); + + dispatch({ + type: COMPATIBILITY_UPDATE_SELECTED_NODE_SUCCESS, + declarationBlocks, + }); + } catch (error) { + dispatch({ type: COMPATIBILITY_UPDATE_SELECTED_NODE_FAILURE, error }); + } + + dispatch({ type: COMPATIBILITY_UPDATE_SELECTED_NODE_COMPLETE }); }; } diff --git a/devtools/client/inspector/compatibility/actions/index.js b/devtools/client/inspector/compatibility/actions/index.js index e21abbda587d..5d88a996cc3d 100644 --- a/devtools/client/inspector/compatibility/actions/index.js +++ b/devtools/client/inspector/compatibility/actions/index.js @@ -9,7 +9,10 @@ const { createEnum } = require("devtools/client/shared/enum"); createEnum( [ // Updates the selected node. - "COMPATIBILITY_UPDATE_SELECTED_NODE", + "COMPATIBILITY_UPDATE_SELECTED_NODE_START", + "COMPATIBILITY_UPDATE_SELECTED_NODE_SUCCESS", + "COMPATIBILITY_UPDATE_SELECTED_NODE_FAILURE", + "COMPATIBILITY_UPDATE_SELECTED_NODE_COMPLETE", // Updates the target browsers. "COMPATIBILITY_UPDATE_TARGET_BROWSERS", diff --git a/devtools/client/inspector/compatibility/reducers/compatibility.js b/devtools/client/inspector/compatibility/reducers/compatibility.js index 4ddf20444ea2..9cea5b214cc7 100644 --- a/devtools/client/inspector/compatibility/reducers/compatibility.js +++ b/devtools/client/inspector/compatibility/reducers/compatibility.js @@ -11,7 +11,8 @@ loader.lazyGetter(this, "mdnCompatibility", () => { }); const { - COMPATIBILITY_UPDATE_SELECTED_NODE, + COMPATIBILITY_UPDATE_SELECTED_NODE_SUCCESS, + COMPATIBILITY_UPDATE_SELECTED_NODE_FAILURE, COMPATIBILITY_UPDATE_TARGET_BROWSERS, } = require("../actions/index"); @@ -22,9 +23,16 @@ const INITIAL_STATE = { }; const reducers = { - [COMPATIBILITY_UPDATE_SELECTED_NODE](state, data) { + [COMPATIBILITY_UPDATE_SELECTED_NODE_SUCCESS](state, data) { return updateSelectedNodeIssues(state, data); }, + [COMPATIBILITY_UPDATE_SELECTED_NODE_FAILURE](state, { error }) { + console.error( + `[COMPATIBILITY_UPDATE_SELECTED_NODE_FAILURE] ${error.message}` + ); + console.error(error.stack); + return state; + }, [COMPATIBILITY_UPDATE_TARGET_BROWSERS](state, data) { return updateSelectedNodeIssues(state, data); }, diff --git a/devtools/client/inspector/compatibility/test/browser/browser.ini b/devtools/client/inspector/compatibility/test/browser/browser.ini index 44eb9b4e55fc..f2205a99a88a 100644 --- a/devtools/client/inspector/compatibility/test/browser/browser.ini +++ b/devtools/client/inspector/compatibility/test/browser/browser.ini @@ -12,6 +12,7 @@ support-files = [browser_compatibility_css-property_issue.js] [browser_compatibility_event_new-node.js] +[browser_compatibility_event_new-node_without-connection.js] [browser_compatibility_event_rule-change.js] [browser_compatibility_preference.js] [browser_compatibility_unsupported-browsers_all.js] diff --git a/devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_new-node_without-connection.js b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_new-node_without-connection.js new file mode 100644 index 000000000000..c2d5b22868e6 --- /dev/null +++ b/devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_new-node_without-connection.js @@ -0,0 +1,32 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test whether no errors occur when reloading the browsing page. + +const { + COMPATIBILITY_UPDATE_SELECTED_NODE_FAILURE, +} = require("devtools/client/inspector/compatibility/actions/index"); + +add_task(async function() { + const tab = await addTab("data:text/html;charset=utf-8,test"); + const { inspector } = await openCompatibilityView(); + + let isFailureActionFired = false; + waitForDispatch( + inspector.store, + COMPATIBILITY_UPDATE_SELECTED_NODE_FAILURE + ).then(() => { + isFailureActionFired = true; + }); + + info("Reload the browsing page"); + const onReloaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); + const onUpdateAction = waitForUpdateSelectedNodeAction(inspector.store); + gBrowser.reloadTab(tab); + await Promise.all([onReloaded, onUpdateAction]); + + info("Check whether the failure action will be fired or not"); + ok(!isFailureActionFired, "No error occurred"); +}); diff --git a/devtools/client/inspector/compatibility/test/browser/head.js b/devtools/client/inspector/compatibility/test/browser/head.js index fd28e5332f66..ac783ae9082d 100644 --- a/devtools/client/inspector/compatibility/test/browser/head.js +++ b/devtools/client/inspector/compatibility/test/browser/head.js @@ -11,6 +11,10 @@ Services.scriptloader.loadSubScript( this ); +const { + COMPATIBILITY_UPDATE_SELECTED_NODE_COMPLETE, +} = require("devtools/client/inspector/compatibility/actions/index"); + const { toCamelCase, } = require("devtools/client/inspector/compatibility/utils/cases"); @@ -20,6 +24,7 @@ async function openCompatibilityView() { await pushPref("devtools.inspector.compatibility.enabled", true); const { inspector } = await openInspectorSidebarTab("compatibilityview"); + await waitForUpdateSelectedNodeAction(inspector.store); const panel = inspector.panelDoc.querySelector( "#compatibilityview-panel .inspector-tabpanel" ); @@ -66,3 +71,32 @@ async function assertIssueList(panel, expectedIssues) { } } } + +/** + * Return a promise which waits for COMPATIBILITY_UPDATE_SELECTED_NODE_COMPLETE action. + * + * @param {Object} store + * @return {Promise} + */ +function waitForUpdateSelectedNodeAction(store) { + return waitForDispatch(store, COMPATIBILITY_UPDATE_SELECTED_NODE_COMPLETE); +} + +/** + * Return a promise which waits for given action type. + * + * @param {Object} store + * @param {Object} type + * @return {Promise} + */ +function waitForDispatch(store, type) { + return new Promise(resolve => { + store.dispatch({ + type: "@@service/waitUntil", + predicate: action => action.type === type, + run: (dispatch, getState, action) => { + resolve(action); + }, + }); + }); +} diff --git a/dom/ipc/BrowserBridgeParent.cpp b/dom/ipc/BrowserBridgeParent.cpp index f1754ea4eb11..e4c042ac3ab1 100644 --- a/dom/ipc/BrowserBridgeParent.cpp +++ b/dom/ipc/BrowserBridgeParent.cpp @@ -140,9 +140,7 @@ void BrowserBridgeParent::Destroy() { IPCResult BrowserBridgeParent::RecvShow(const ScreenIntSize& aSize, const bool& aParentIsActive, const nsSizeMode& aSizeMode) { - if (!mBrowserParent->AttachLayerManager()) { - MOZ_CRASH(); - } + mBrowserParent->AttachLayerManager(); Unused << mBrowserParent->SendShow(aSize, mBrowserParent->GetShowInfo(), aParentIsActive, aSizeMode); return IPC_OK(); diff --git a/gfx/wr/example-compositor/compositor-windows/src/lib.cpp b/gfx/wr/example-compositor/compositor-windows/src/lib.cpp index fceedaf5a244..2c64aaeb2fd8 100644 --- a/gfx/wr/example-compositor/compositor-windows/src/lib.cpp +++ b/gfx/wr/example-compositor/compositor-windows/src/lib.cpp @@ -10,13 +10,18 @@ #include #include #include +#include #define EGL_EGL_PROTOTYPES 1 #define EGL_EGLEXT_PROTOTYPES 1 +#define GL_GLEXT_PROTOTYPES 1 #include "EGL/egl.h" #include "EGL/eglext.h" #include "EGL/eglext_angle.h" #include "GL/gl.h" +#include "GLES/gl.h" +#include "GLES/glext.h" +#include "GLES3/gl3.h" // The OS compositor representation of a picture cache tile. struct Tile { @@ -26,6 +31,13 @@ struct Tile { IDCompositionVisual2 *pVisual; }; +struct CachedFrameBuffer { + int width; + int height; + GLuint fboId; + GLuint depthRboId; +}; + struct Window { // Win32 window details HWND hWnd; @@ -50,8 +62,9 @@ struct Window { EGLSurface fb_surface; // The currently bound surface, valid during bind() and unbind() - EGLSurface current_surface; IDCompositionSurface *pCurrentSurface; + EGLImage mEGLImage; + GLuint mColorRBO; // The root of the DC visual tree. Nothing is drawn on this, but // all child tiles are parented to here. @@ -59,10 +72,50 @@ struct Window { IDCompositionVisualDebug *pVisualDebug; // Maps the WR surface IDs to the DC representation of each tile. std::map tiles; + std::vector mFrameBuffers; }; static const wchar_t *CLASS_NAME = L"WR DirectComposite"; +static GLuint GetOrCreateFbo(Window *window, int aWidth, int aHeight) { + GLuint fboId = 0; + + // Check if we have a cached FBO with matching dimensions + for (auto it = window->mFrameBuffers.begin(); it != window->mFrameBuffers.end(); ++it) { + if (it->width == aWidth && it->height == aHeight) { + fboId = it->fboId; + break; + } + } + + // If not, create a new FBO with attached depth buffer + if (fboId == 0) { + // Create the depth buffer + GLuint depthRboId; + glGenRenderbuffers(1, &depthRboId); + glBindRenderbuffer(GL_RENDERBUFFER, depthRboId); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, + aWidth, aHeight); + + // Create the framebuffer and attach the depth buffer to it + glGenFramebuffers(1, &fboId); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId); + glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, depthRboId); + + // Store this in the cache for future calls. + CachedFrameBuffer frame_buffer_info; + frame_buffer_info.width = aWidth; + frame_buffer_info.height = aHeight; + frame_buffer_info.fboId = fboId; + frame_buffer_info.depthRboId = depthRboId; + window->mFrameBuffers.push_back(frame_buffer_info); + } + + return fboId; +} + static LRESULT CALLBACK WndProc( HWND hwnd, UINT message, @@ -86,6 +139,7 @@ extern "C" { window->width = width; window->height = height; window->enable_compositor = enable_compositor; + window->mEGLImage = EGL_NO_IMAGE; WNDCLASSEX wcex = { sizeof(WNDCLASSEX) }; wcex.style = CS_HREDRAW | CS_VREDRAW; @@ -284,7 +338,7 @@ extern "C" { delete window; } - bool com_dc_tick(Window *window) { + bool com_dc_tick(Window *) { // Check and dispatch the windows event loop MSG msg; while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { @@ -356,7 +410,7 @@ extern "C" { } // Bind a DC surface to allow issuing GL commands to it - void com_dc_bind_surface( + GLuint com_dc_bind_surface( Window *window, uint64_t id, int *x_offset, @@ -395,35 +449,44 @@ extern "C" { offset.y -= dirty_y0; assert(SUCCEEDED(hr)); pTexture->GetDesc(&desc); - - // Construct an EGL off-screen surface that is bound to the DC surface - EGLint buffer_attribs[] = { - EGL_WIDTH, desc.Width, - EGL_HEIGHT, desc.Height, - EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE, EGL_TRUE, - EGL_NONE - }; - - window->current_surface = eglCreatePbufferFromClientBuffer( - window->EGLDisplay, - EGL_D3D_TEXTURE_ANGLE, - pTexture, - window->config, - buffer_attribs - ); - assert(window->current_surface != EGL_NO_SURFACE); - - // Make EGL current on the DC surface - EGLBoolean ok = eglMakeCurrent( - window->EGLDisplay, - window->current_surface, - window->current_surface, - window->EGLContext - ); - assert(ok); - *x_offset = offset.x; *y_offset = offset.y; + + // Construct an EGLImage wrapper around the D3D texture for ANGLE. + const EGLAttrib attribs[] = { EGL_NONE }; + window->mEGLImage = eglCreateImage( + window->EGLDisplay, + EGL_NO_CONTEXT, + EGL_D3D11_TEXTURE_ANGLE, + static_cast(pTexture), + attribs + ); + + // Get the current FBO and RBO id, so we can restore them later + GLint currentFboId, currentRboId; + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤tFboId); + glGetIntegerv(GL_RENDERBUFFER_BINDING, ¤tRboId); + + // Create a render buffer object that is backed by the EGL image. + glGenRenderbuffers(1, &window->mColorRBO); + glBindRenderbuffer(GL_RENDERBUFFER, window->mColorRBO); + glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, window->mEGLImage); + + // Get or create an FBO for the specified dimensions + GLuint fboId = GetOrCreateFbo(window, desc.Width, desc.Height); + + // Attach the new renderbuffer to the FBO + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId); + glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, + window->mColorRBO); + + // Restore previous FBO and RBO bindings + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, currentFboId); + glBindRenderbuffer(GL_RENDERBUFFER, currentRboId); + + return fboId; } // Unbind a currently bound DC surface @@ -431,7 +494,11 @@ extern "C" { HRESULT hr = window->pCurrentSurface->EndDraw(); assert(SUCCEEDED(hr)); - eglDestroySurface(window->EGLDisplay, window->current_surface); + glDeleteRenderbuffers(1, &window->mColorRBO); + window->mColorRBO = 0; + + eglDestroyImage(window->EGLDisplay, window->mEGLImage); + window->mEGLImage = EGL_NO_IMAGE; } // At the start of a transaction, remove all visuals from the tree. @@ -467,8 +534,8 @@ extern "C" { // Place the visual - this changes frame to frame based on scroll position // of the slice. - int offset_x = x + window->client_rect.left; - int offset_y = y + window->client_rect.top; + float offset_x = (float) (x + window->client_rect.left); + float offset_y = (float) (y + window->client_rect.top); tile.pVisual->SetOffsetX(offset_x); tile.pVisual->SetOffsetY(offset_y); diff --git a/gfx/wr/example-compositor/compositor-windows/src/lib.rs b/gfx/wr/example-compositor/compositor-windows/src/lib.rs index 4ccf780df5df..4362dd3eb481 100644 --- a/gfx/wr/example-compositor/compositor-windows/src/lib.rs +++ b/gfx/wr/example-compositor/compositor-windows/src/lib.rs @@ -50,7 +50,7 @@ extern { dirty_y0: i32, dirty_width: i32, dirty_height: i32, - ); + ) -> u32; fn com_dc_unbind_surface(window: *mut Window); fn com_dc_begin_transaction(window: *mut Window); @@ -130,12 +130,12 @@ pub fn bind_surface( dirty_y0: i32, dirty_width: i32, dirty_height: i32, -) -> (i32, i32) { +) -> (u32, i32, i32) { unsafe { let mut x_offset = 0; let mut y_offset = 0; - com_dc_bind_surface( + let fbo_id = com_dc_bind_surface( window, id, &mut x_offset, @@ -146,7 +146,7 @@ pub fn bind_surface( dirty_height, ); - (x_offset, y_offset) + (fbo_id, x_offset, y_offset) } } diff --git a/gfx/wr/example-compositor/compositor/src/main.rs b/gfx/wr/example-compositor/compositor/src/main.rs index bab9ac42aab1..e0393f9f3c6d 100644 --- a/gfx/wr/example-compositor/compositor/src/main.rs +++ b/gfx/wr/example-compositor/compositor/src/main.rs @@ -65,7 +65,7 @@ impl webrender::Compositor for DirectCompositeInterface { id: webrender::NativeSurfaceId, dirty_rect: DeviceIntRect, ) -> webrender::NativeSurfaceInfo { - let (x, y) = compositor::bind_surface( + let (fbo_id, x, y) = compositor::bind_surface( self.window, id.0, dirty_rect.origin.x, @@ -76,7 +76,7 @@ impl webrender::Compositor for DirectCompositeInterface { webrender::NativeSurfaceInfo { origin: DeviceIntPoint::new(x, y), - fbo_id: 0, + fbo_id, } } diff --git a/js/src/frontend/BinASTRuntimeSupport.h b/js/src/frontend/BinASTRuntimeSupport.h index d6c333865830..695bafbbcc33 100644 --- a/js/src/frontend/BinASTRuntimeSupport.h +++ b/js/src/frontend/BinASTRuntimeSupport.h @@ -116,7 +116,13 @@ class BinASTSourceMetadata { public: BinASTSourceMetadata() = delete; explicit BinASTSourceMetadata(Type type) : type_(type) {} +#ifdef JS_BUILD_BINAST ~BinASTSourceMetadata(); +#else + // If JS_BUILD_BINAST isn't defined, BinASTRuntimeSupport.cpp isn't built, + // but still the destructor is referred from ScriptSource::BinAST. + ~BinASTSourceMetadata() {} +#endif // JS_BUILD_BINAST Type type() const { return type_; } diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 7fdce3420613..0fbdf71d6474 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -10981,7 +10981,7 @@ int main(int argc, char** argv, char** envp) { "Format of BinAST file (multipart/context)") || #else !op.addMultiStringOption('B', "binast", "", "No-op") || - !op.addStringOption('\0', "binast-format", "No-op") || + !op.addStringOption('\0', "binast-format", "[format]", "No-op") || #endif // JS_BUILD_BINAST !op.addMultiStringOption('e', "execute", "CODE", "Inline code to run") || !op.addBoolOption('i', "shell", "Enter prompt after running code") || diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index c52a95d71c20..fa71c3d4e359 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -4151,6 +4151,12 @@ value: false mirror: always +# Whether we allow advanced layers with fission +- name: layers.advanced.fission.enabled + type: bool + value: false + mirror: always + # Whether we allow AMD switchable graphics. - name: layers.amd-switchable-gfx.enabled type: bool diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp index f2588d3b6514..1ce3100019c9 100644 --- a/parser/html/nsHtml5TreeOpExecutor.cpp +++ b/parser/html/nsHtml5TreeOpExecutor.cpp @@ -450,6 +450,16 @@ void nsHtml5TreeOpExecutor::RunFlushLoop() { // Now parse content left in the document.write() buffer queue if any. // This may generate tree ops on its own or dequeue a speculation. nsresult rv = GetParser()->ParseUntilBlocked(); + + // ParseUntilBlocked flushes operations from the stage to the OpQueue. + // Those operations may have accompanying speculative operations. + // If so, we have to flush those speculative loads so that we maintain + // the invariant that no speculative load starts after the corresponding + // normal load for the same URL. See + // https://bugzilla.mozilla.org/show_bug.cgi?id=1513292#c80 + // for a more detailed explanation of why this is necessary. + FlushSpeculativeLoads(); + if (NS_FAILED(rv)) { MarkAsBroken(rv); return; diff --git a/services/fxaccounts/FxAccounts.jsm b/services/fxaccounts/FxAccounts.jsm index 61b39d665823..13c1842679a1 100644 --- a/services/fxaccounts/FxAccounts.jsm +++ b/services/fxaccounts/FxAccounts.jsm @@ -874,7 +874,7 @@ FxAccountsInternal.prototype = { _telemetry: null, get telemetry() { if (!this._telemetry) { - this._telemetry = new FxAccountsTelemetry(); + this._telemetry = new FxAccountsTelemetry(this); } return this._telemetry; }, diff --git a/services/fxaccounts/FxAccountsTelemetry.jsm b/services/fxaccounts/FxAccountsTelemetry.jsm index 8f1dadedd7fa..5e445da74e0c 100644 --- a/services/fxaccounts/FxAccountsTelemetry.jsm +++ b/services/fxaccounts/FxAccountsTelemetry.jsm @@ -9,13 +9,25 @@ // sanely shared (eg, services-common?), but let's wait and see where we end up // first... -// We use this observers module because we leverage its support for richer -// "subject" data. -const { Observers } = ChromeUtils.import( - "resource://services-common/observers.js" +const { XPCOMUtils } = ChromeUtils.import( + "resource://gre/modules/XPCOMUtils.jsm" ); +XPCOMUtils.defineLazyModuleGetters(this, { + log: "resource://gre/modules/FxAccountsCommon.js", + // We use this observers module because we leverage its support for richer + // "subject" data. + Observers: "resource://services-common/observers.js", + Services: "resource://gre/modules/Services.jsm", +}); + class FxAccountsTelemetry { + constructor(fxai) { + this._fxai = fxai; + Services.telemetry.setEventRecordingEnabled("fxa", true); + } + + // Records an event *in the Fxa/Sync ping*. recordEvent(object, method, value, extra = undefined) { // We need to ensure the telemetry module is loaded. ChromeUtils.import("resource://services-sync/telemetry.js"); @@ -50,6 +62,81 @@ class FxAccountsTelemetry { } return null; } + + // Record the connection of FxA or one of its services. + // Note that you must call this before performing the actual connection + // or we may record incorrect data - for example, we will not be able to + // determine whether FxA itself was connected before this call. + // + // Currently sends an event in the main telemetry event ping rather than the + // FxA/Sync ping (although this might change in the future) + // + // @param services - An array of service names which should be recorded. FxA + // itself is not counted as a "service" - ie, an empty array should be passed + // if the account is connected without anything else . + // + // @param how - How the connection was done. + async recordConnection(services, how = null) { + try { + let extra = {}; + // Record that fxa was connected if it isn't currently - it will be soon. + if (!(await this._fxai.getUserAccountData())) { + extra.fxa = "true"; + } + // Events.yaml only declares "sync" as a valid service. + if (services.includes("sync")) { + extra.sync = "true"; + } + Services.telemetry.recordEvent("fxa", "connect", "account", how, extra); + } catch (ex) { + log.error("Failed to record connection telemetry", ex); + console.error("Failed to record connection telemetry", ex); + } + } + + // Record the disconnection of FxA or one of its services. + // Note that you must call this before performing the actual disconnection + // or we may record incomplete data - for example, if this is called after + // disconnection, we've almost certainly lost the ability to record what + // services were enabled prior to disconnection. + // + // Currently sends an event in the main telemetry event ping rather than the + // FxA/Sync ping (although this might change in the future) + // + // @param service - the service being disconnected. If null, the account + // itself is being disconnected, so all connected services are too. + // + // @param how - how the disconnection was done. + async recordDisconnection(service = null, how = null) { + try { + let extra = {}; + if (!service) { + extra.fxa = "true"; + // We need a way to enumerate all services - but for now we just hard-code + // all possibilities here. + if (Services.prefs.prefHasUserValue("services.sync.username")) { + extra.sync = "true"; + } + } else if (service == "sync") { + extra[service] = "true"; + } else { + // Events.yaml only declares "sync" as a valid service. + log.warn( + `recordDisconnection has invalid value for service: ${service}` + ); + } + Services.telemetry.recordEvent( + "fxa", + "disconnect", + "account", + how, + extra + ); + } catch (ex) { + log.error("Failed to record disconnection telemetry", ex); + console.error("Failed to record disconnection telemetry", ex); + } + } } var EXPORTED_SYMBOLS = ["FxAccountsTelemetry"]; diff --git a/services/fxaccounts/FxAccountsWebChannel.jsm b/services/fxaccounts/FxAccountsWebChannel.jsm index 5c365a6c4045..ccae44dd9f39 100644 --- a/services/fxaccounts/FxAccountsWebChannel.jsm +++ b/services/fxaccounts/FxAccountsWebChannel.jsm @@ -434,6 +434,11 @@ this.FxAccountsWebChannelHelpers.prototype = { // Remember who it was so we can log out next time. this.setPreviousAccountNameHashPref(accountData.email); + await this._fxAccounts.telemetry.recordConnection( + Object.keys(requestedServices || {}), + "webchannel" + ); + // A sync-specific hack - we want to ensure sync has been initialized // before we set the signed-in user. // XXX - probably not true any more, especially now we have observerPreloads @@ -479,17 +484,15 @@ this.FxAccountsWebChannelHelpers.prototype = { * * @param the uid of the account which have been logged out */ - logout(uid) { - return this._fxAccounts._internal - .getUserAccountData(["uid"]) - .then(userData => { - if (userData && userData.uid === uid) { - // true argument is `localOnly`, because server-side stuff - // has already been taken care of by the content server - return fxAccounts.signOut(true); - } - return null; - }); + async logout(uid) { + let fxa = this._fxAccounts; + let userData = await fxa._internal.getUserAccountData(["uid"]); + if (userData && userData.uid === uid) { + await fxa.telemetry.recordDisconnection(null, "webchannel"); + // true argument is `localOnly`, because server-side stuff + // has already been taken care of by the content server + await fxa.signOut(true); + } }, /** diff --git a/services/fxaccounts/tests/xpcshell/test_web_channel.js b/services/fxaccounts/tests/xpcshell/test_web_channel.js index c66cac22dbde..6f3917ed55bf 100644 --- a/services/fxaccounts/tests/xpcshell/test_web_channel.js +++ b/services/fxaccounts/tests/xpcshell/test_web_channel.js @@ -396,6 +396,9 @@ add_task(async function test_helpers_login_without_customize_sync() { }); }, }, + telemetry: { + recordConnection: sinon.spy(), + }, }, weaveXPCOM: { whenLoaded() {}, @@ -415,6 +418,9 @@ add_task(async function test_helpers_login_without_customize_sync() { verifiedCanLinkAccount: true, customizeSync: false, }); + Assert.ok( + helpers._fxAccounts.telemetry.recordConnection.calledWith([], "webchannel") + ); }); add_task(async function test_helpers_login_with_customize_sync() { @@ -433,6 +439,9 @@ add_task(async function test_helpers_login_with_customize_sync() { }); }, }, + telemetry: { + recordConnection: sinon.spy(), + }, }, weaveXPCOM: { whenLoaded() {}, @@ -449,6 +458,9 @@ add_task(async function test_helpers_login_with_customize_sync() { verifiedCanLinkAccount: true, customizeSync: true, }); + Assert.ok( + helpers._fxAccounts.telemetry.recordConnection.calledWith([], "webchannel") + ); }); add_task( @@ -469,6 +481,9 @@ add_task( }); }, }, + telemetry: { + recordConnection: sinon.spy(), + }, }, weaveXPCOM: { whenLoaded() {}, @@ -542,6 +557,12 @@ add_task( ); Assert.equal(Services.prefs.getBoolPref("services.sync.engine.tabs"), true); Assert.ok(configured, "sync was configured"); + Assert.ok( + helpers._fxAccounts.telemetry.recordConnection.calledWith( + ["sync"], + "webchannel" + ) + ); } ); @@ -556,6 +577,9 @@ add_task(async function test_helpers_login_with_offered_sync_engines() { resolve(accountData); }, }, + telemetry: { + recordConnection() {}, + }, }, weaveXPCOM: { whenLoaded() {}, @@ -610,6 +634,9 @@ add_task(async function test_helpers_login_nothing_offered() { resolve(accountData); }, }, + telemetry: { + recordConnection() {}, + }, }, weaveXPCOM: { whenLoaded() {}, diff --git a/testing/web-platform/tests/css/css-grid/parsing/grid-area-valid.html b/testing/web-platform/tests/css/css-grid/parsing/grid-area-valid.html index abe58951efeb..9f93e6325b1b 100644 --- a/testing/web-platform/tests/css/css-grid/parsing/grid-area-valid.html +++ b/testing/web-platform/tests/css/css-grid/parsing/grid-area-valid.html @@ -76,11 +76,12 @@ test_valid_value("grid-row", "2 i / auto", "2 i"); test_valid_value("grid-row", "1 / auto", "1"); test_valid_value("grid-column", "2 j / span 3 k"); - // https://github.com/w3c/csswg-drafts/issues/2858 -// '\\31 st' in Blink, Firefox, '1st' in Edge, '"1st"' in Safari. -test_valid_value("grid-column-end", "\\31st", ["\\31 st", "1st", '"1st"']); -test_valid_value("grid-column-end", "\\31 st", ["\\31 st", "1st", '"1st"']); +// '\\31 st' in Blink, Firefox, EdgeHTML and Safari serialize invalid values. +test_valid_value("grid-column-end", "\\31st", ["\\31 st", "\\31st"]); +test_valid_value("grid-column-end", "\\31 st", ["\\31 st", "\\31st"]); +test_valid_value("grid-column", "\\31st / \\31 st", ["\\31 st", "\\31st"]); + diff --git a/toolkit/components/telemetry/Events.yaml b/toolkit/components/telemetry/Events.yaml index 03803ffbd43d..60df034cdd7c 100644 --- a/toolkit/components/telemetry/Events.yaml +++ b/toolkit/components/telemetry/Events.yaml @@ -656,6 +656,26 @@ pwmgr: release_channel_collection: opt-out expiry_version: never +fxa: + connect: + objects: ["account"] + methods: ["connect", "disconnect"] + description: > + Records when a Firefox Account, or a Firefox Account service, is explicitly + connected or disconnected from the browser via an intentional user action. + extra_keys: + fxa: Whether the account itself was connected or disconnected. + sync: Whether sync was connected or disconnected. + products: + - "firefox" + - "fennec" + - "geckoview" + record_in_processes: ["main"] + bug_numbers: [1595954] + notification_emails: ["sync-dev@mozilla.org"] + release_channel_collection: opt-out + expiry_version: never + fxa_avatar_menu: click: objects: [ diff --git a/widget/nsBaseWidget.cpp b/widget/nsBaseWidget.cpp index 4ed9df6cc2cd..1cd861843258 100644 --- a/widget/nsBaseWidget.cpp +++ b/widget/nsBaseWidget.cpp @@ -54,6 +54,7 @@ #include "mozilla/StaticPrefs_apz.h" #include "mozilla/StaticPrefs_dom.h" #include "mozilla/StaticPrefs_layout.h" +#include "mozilla/StaticPrefs_layers.h" #include "mozilla/Unused.h" #include "mozilla/IMEStateManager.h" #include "mozilla/VsyncDispatcher.h" @@ -72,7 +73,6 @@ #include "mozilla/gfx/gfxVars.h" #include "mozilla/Move.h" #include "mozilla/Sprintf.h" -#include "mozilla/StaticPrefs_layout.h" #include "mozilla/webrender/WebRenderTypes.h" #include "nsRefPtrHashtable.h" #include "TouchEvents.h" @@ -172,6 +172,7 @@ nsBaseWidget::nsBaseWidget() mPopupLevel(ePopupLevelTop), mPopupType(ePopupTypeAny), mHasRemoteContent(false), + mFissionWindow(false), mUpdateCursor(true), mUseAttachedEvents(false), mIMEHasFocus(false), @@ -391,6 +392,7 @@ void nsBaseWidget::BaseCreate(nsIWidget* aParent, nsWidgetInitData* aInitData) { mPopupLevel = aInitData->mPopupLevel; mPopupType = aInitData->mPopupHint; mHasRemoteContent = aInitData->mHasRemoteContent; + mFissionWindow = aInitData->mFissionWindow; } if (aParent) { @@ -1213,7 +1215,11 @@ already_AddRefed nsBaseWidget::CreateCompositorSession( bool enableAPZ = UseAPZ(); CompositorOptions options(enableAPZ, enableWR); - bool enableAL = gfx::gfxConfig::IsEnabled(gfx::Feature::ADVANCED_LAYERS); + // Bug 1588484 - Advanced Layers is currently disabled for fission windows, + // since it doesn't properly support nested RefLayers. + bool enableAL = + gfx::gfxConfig::IsEnabled(gfx::Feature::ADVANCED_LAYERS) && + (!mFissionWindow || StaticPrefs::layers_advanced_fission_enabled()); options.SetUseAdvancedLayers(enableAL); #ifdef MOZ_WIDGET_ANDROID diff --git a/widget/nsBaseWidget.h b/widget/nsBaseWidget.h index 02e6470539ac..9ebfde22bbcb 100644 --- a/widget/nsBaseWidget.h +++ b/widget/nsBaseWidget.h @@ -691,6 +691,7 @@ class nsBaseWidget : public nsIWidget, public nsSupportsWeakReference { nsPopupType mPopupType; SizeConstraints mSizeConstraints; bool mHasRemoteContent; + bool mFissionWindow; bool mUpdateCursor; bool mUseAttachedEvents; diff --git a/widget/nsWidgetInitData.h b/widget/nsWidgetInitData.h index e40199cfb807..37bb2ab2b50b 100644 --- a/widget/nsWidgetInitData.h +++ b/widget/nsWidgetInitData.h @@ -112,7 +112,8 @@ struct nsWidgetInitData { mMouseTransparent(false), mHasRemoteContent(false), mAlwaysOnTop(false), - mPIPWindow(false) {} + mPIPWindow(false), + mFissionWindow(false) {} nsWindowType mWindowType; nsBorderStyle mBorderStyle; @@ -140,6 +141,8 @@ struct nsWidgetInitData { bool mAlwaysOnTop; // Is PictureInPicture window bool mPIPWindow; + // True if fission is enabled for this window + bool mFissionWindow; }; #endif // nsWidgetInitData_h__ diff --git a/xpfe/appshell/nsAppShellService.cpp b/xpfe/appshell/nsAppShellService.cpp index 9dbb20e1cb45..137c8ffe247e 100644 --- a/xpfe/appshell/nsAppShellService.cpp +++ b/xpfe/appshell/nsAppShellService.cpp @@ -593,6 +593,9 @@ nsresult nsAppShellService::JustCreateTopWindow( if (aChromeMask & nsIWebBrowserChrome::CHROME_ALWAYS_ON_TOP) widgetInitData.mAlwaysOnTop = true; + if (aChromeMask & nsIWebBrowserChrome::CHROME_FISSION_WINDOW) + widgetInitData.mFissionWindow = true; + #ifdef MOZ_WIDGET_GTK // Linux/Gtk PIP window support. It's Chrome Toplevel window, always on top // and without any bar.