author | Andreea Pavel <apavel@mozilla.com> |
Thu, 07 Nov 2019 11:47:48 +0200 | |
changeset 501035 | d271c572a9bcd008ed14bf104b2eb81949952e4c |
parent 500872 | e8b7c48d4e7ed1b63aeedff379b51e566ea499d9 (current diff) |
parent 501034 | 85aa4fa5722bdcb6e0d13f29951772d3c7806e42 (diff) |
child 501044 | 8c32b5d7296d84dedb3a9678ffda886aba35f203 |
push id | 36778 |
push user | apavel@mozilla.com |
push date | Thu, 07 Nov 2019 09:49:05 +0000 |
treeherder | mozilla-central@d271c572a9bc [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 72.0a1 |
first release with | nightly linux32
d271c572a9bc
/
72.0a1
/
20191107094905
/
files
nightly linux64
d271c572a9bc
/
72.0a1
/
20191107094905
/
files
nightly mac
d271c572a9bc
/
72.0a1
/
20191107094905
/
files
nightly win32
d271c572a9bc
/
72.0a1
/
20191107094905
/
files
nightly win64
d271c572a9bc
/
72.0a1
/
20191107094905
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
72.0a1
/
20191107094905
/
pushlog to previous
nightly linux64
72.0a1
/
20191107094905
/
pushlog to previous
nightly mac
72.0a1
/
20191107094905
/
pushlog to previous
nightly win32
72.0a1
/
20191107094905
/
pushlog to previous
nightly win64
72.0a1
/
20191107094905
/
pushlog to previous
|
--- a/.eslintrc.js +++ b/.eslintrc.js @@ -231,17 +231,16 @@ module.exports = { "dom/tests/mochitest/**", "dom/u2f/**", "dom/vr/**", "dom/webauthn/**", "dom/webgpu/**", "dom/websocket/**", "dom/workers/**", "dom/worklet/**", - "dom/xbl/**", "dom/xml/**", "dom/xslt/**", "dom/xul/**", ], "rules": { "consistent-return": "off", "mozilla/avoid-removeChild": "off", "mozilla/consistent-if-bracing": "off",
--- a/accessible/ipc/DocAccessibleParent.cpp +++ b/accessible/ipc/DocAccessibleParent.cpp @@ -134,27 +134,28 @@ uint32_t DocAccessibleParent::AddSubtree if (pending.mParentID == newChild.ID()) { if (!pending.mChildDoc->IsShutdown()) { AddChildDoc(pending.mChildDoc, pending.mParentID, false); } mPendingChildDocs.RemoveElementAt(index); break; } } + DebugOnly<bool> isOuterDoc = newProxy->ChildrenCount() == 1; uint32_t accessibles = 1; uint32_t kids = newChild.ChildrenCount(); for (uint32_t i = 0; i < kids; i++) { uint32_t consumed = AddSubtree(newProxy, aNewTree, aIdx + accessibles, i); if (!consumed) return 0; accessibles += consumed; } - MOZ_ASSERT(newProxy->ChildrenCount() == kids); + MOZ_ASSERT((isOuterDoc && kids == 0) || newProxy->ChildrenCount() == kids); return accessibles; } mozilla::ipc::IPCResult DocAccessibleParent::RecvHideEvent( const uint64_t& aRootID, const bool& aFromUser) { if (mShutdown) return IPC_OK();
--- a/accessible/mac/Platform.mm +++ b/accessible/mac/Platform.mm @@ -53,18 +53,21 @@ void ProxyCreated(ProxyAccessible* aProx // will be a non-remote accessible. Accessible* outerDoc = aProxy->OuterDocOfRemoteBrowser(); if (outerDoc) { nativeParent = GetNativeFromGeckoAccessible(outerDoc); } } else { // Non-top level proxies need proxy parents' children invalidated. ProxyAccessible* parent = aProxy->Parent(); - nativeParent = GetNativeFromProxy(parent); - NS_ASSERTION(parent, "a non-top-level proxy is missing a parent?"); + MOZ_ASSERT(parent || + // It's expected that an OOP iframe might not have a parent yet. + (aProxy->IsDoc() && aProxy->AsDoc()->IsTopLevelInContentProcess()), + "a non-top-level proxy is missing a parent?"); + nativeParent = parent ? GetNativeFromProxy(parent) : nullptr; } if (nativeParent) { [nativeParent invalidateChildren]; } } void ProxyDestroyed(ProxyAccessible* aProxy) { @@ -93,16 +96,31 @@ void ProxyDestroyed(ProxyAccessible* aPr aProxy->SetWrapper(0); if (nativeParent) { [nativeParent invalidateChildren]; } } void ProxyEvent(ProxyAccessible* aProxy, uint32_t aEventType) { + if (aEventType == nsIAccessibleEvent::EVENT_REORDER && aProxy->ChildrenCount() == 1 && + aProxy->ChildAt(0)->IsDoc()) { + // This is a remote OuterDocAccessible. The reorder event indicates that Its + // embedded document has been added or changed. If the document itself is + // an existing Accessible, ProxyCreated won't have been called, so we won't + // have invalidated native children. This can happen for in-process iframes + // if the OuterDocAccessible is re-created (e.g. due to layout reflow). + // It always happens for out-of-process iframes, as we must always call + // ProxyCreated before DocAccessibleParent::AddChildDoc for those. + mozAccessible* wrapper = GetNativeFromProxy(aProxy); + if (wrapper) { + [wrapper invalidateChildren]; + } + } + // ignore everything but focus-changed, value-changed, caret and selection // events for now. if (aEventType != nsIAccessibleEvent::EVENT_FOCUS && aEventType != nsIAccessibleEvent::EVENT_VALUE_CHANGE && aEventType != nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE && aEventType != nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED && aEventType != nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED) return;
--- a/browser/base/content/browser-siteProtections.js +++ b/browser/base/content/browser-siteProtections.js @@ -1231,28 +1231,40 @@ var gProtectionsHandler = { )); }, get _protectionsPopupSiteNotWorkingTPSwitch() { delete this._protectionsPopupSiteNotWorkingTPSwitch; return (this._protectionsPopupSiteNotWorkingTPSwitch = document.getElementById( "protections-popup-siteNotWorking-tp-switch" )); }, + get _protectionsPopupSiteNotWorkingReportError() { + delete this._protectionsPopupSiteNotWorkingReportError; + return (this._protectionsPopupSiteNotWorkingReportError = document.getElementById( + "protections-popup-sendReportView-report-error" + )); + }, get _protectionsPopupSendReportLearnMore() { delete this._protectionsPopupSendReportLearnMore; return (this._protectionsPopupSendReportLearnMore = document.getElementById( "protections-popup-sendReportView-learn-more" )); }, get _protectionsPopupSendReportURL() { delete this._protectionsPopupSendReportURL; return (this._protectionsPopupSendReportURL = document.getElementById( "protections-popup-sendReportView-collection-url" )); }, + get _protectionsPopupSendReportButton() { + delete this._protectionsPopupSendReportButton; + return (this._protectionsPopupSendReportButton = document.getElementById( + "protections-popup-sendReportView-submit" + )); + }, get _trackingProtectionIconTooltipLabel() { delete this._trackingProtectionIconTooltipLabel; return (this._trackingProtectionIconTooltipLabel = document.getElementById( "tracking-protection-icon-tooltip-label" )); }, get noTrackersDetectedDescription() { @@ -2169,17 +2181,22 @@ var gProtectionsHandler = { showSendReportView() { // Save this URI to make sure that the user really only submits the location // they see in the report breakage dialog. this.reportURI = gBrowser.currentURI; let urlWithoutQuery = this.reportURI.asciiSpec.replace( "?" + this.reportURI.query, "" ); + let commentsTextarea = document.getElementById( + "protections-popup-sendReportView-collection-comments" + ); + commentsTextarea.value = ""; this._protectionsPopupSendReportURL.value = urlWithoutQuery; + this._protectionsPopupSiteNotWorkingReportError.hidden = true; this._protectionsPopupMultiView.showSubView( "protections-popup-sendReportView" ); }, toggleBreakageLink() { // The breakage link will only be shown if tracking protection is enabled // for the site and the TP toggle state is on. And we won't show the @@ -2187,16 +2204,17 @@ var gProtectionsHandler = { // know the previous TP state. We check the ContentBlockingAllowList instead // of 'hasException' attribute of the protection popup for the previous // since the 'hasException' will also be toggled as well as toggling the TP // switch. We won't be able to know the previous TP state through the // 'hasException' attribute. So we fallback to check the // ContentBlockingAllowList here. this._protectionsPopupTPSwitchBreakageLink.hidden = ContentBlockingAllowList.includes(gBrowser.selectedBrowser) || + !this._protectionsPopup.hasAttribute("blocking") || !this._protectionsPopupTPSwitch.hasAttribute("enabled"); }, submitBreakageReport(uri) { let reportEndpoint = Services.prefs.getStringPref( this.PREF_REPORT_BREAKAGE_URL ); if (!reportEndpoint) { @@ -2264,38 +2282,41 @@ var gProtectionsHandler = { activatedBlockers.push(blocker.reportBreakageLabel); } } if (activatedBlockers.length) { formData.set("labels", activatedBlockers.join(",")); } + this._protectionsPopupSendReportButton.disabled = true; + fetch(reportEndpoint, { method: "POST", credentials: "omit", body: formData, }) - .then(function(response) { + .then(response => { + this._protectionsPopupSendReportButton.disabled = false; if (!response.ok) { Cu.reportError( `Content Blocking report to ${reportEndpoint} failed with status ${ response.status }` ); + this._protectionsPopupSiteNotWorkingReportError.hidden = false; } else { - // Clear the textarea value when the report is submitted - commentsTextarea.value = ""; + this._protectionsPopup.hidePopup(); + ConfirmationHint.show(this.iconBox, "breakageReport"); } }) .catch(Cu.reportError); }, onSendReportClicked() { - this._protectionsPopup.hidePopup(); this.submitBreakageReport(this.reportURI); }, async maybeUpdateEarliestRecordedDateTooltip() { if (this._hasEarliestRecord) { return; }
--- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -3315,20 +3315,16 @@ function URLBarSetURI(aURI, updatePopupN gURLBar.selectionStart = gURLBar.selectionEnd = 0; } SetPageProxyState(valid ? "valid" : "invalid", updatePopupNotifications); } function losslessDecodeURI(aURI) { let scheme = aURI.scheme; - if (scheme == "moz-action") { - throw new Error("losslessDecodeURI should never get a moz-action URI"); - } - var value = aURI.displaySpec; let decodeASCIIOnly = !["https", "http", "file", "ftp"].includes(scheme); // Try to decode as UTF-8 if there's no encoding sequence that we would break. if (!/%25(?:3B|2F|3F|3A|40|26|3D|2B|24|2C|23)/i.test(value)) { if (decodeASCIIOnly) { // This only decodes ascii characters (hex) 20-7e, except 25 (%). // This avoids both cases stipulated below (%-related issues, and \r, \n
--- a/browser/base/content/browser.xhtml +++ b/browser/base/content/browser.xhtml @@ -72,16 +72,17 @@ persist="screenX screenY width height sizemode" data-l10n-sync="true"> <linkset> <html:link rel="localization" href="branding/brand.ftl"/> <html:link rel="localization" href="browser/branding/sync-brand.ftl"/> <html:link rel="localization" href="browser/browser.ftl"/> <html:link rel="localization" href="browser/menubar.ftl"/> + <html:link rel="localization" href="browser/protectionsPanel.ftl"/> <html:link rel="localization" href="browser/appmenu.ftl"/> <html:link rel="localization" href="browser/readerView.ftl"/> </linkset> # All JS files which are needed by browser.xhtml and other top level windows to # support MacOS specific features *must* go into the global-scripts.inc file so # that they can be shared with macWindow.inc.xul. #include global-scripts.inc
--- a/browser/base/content/test/siteProtections/browser.ini +++ b/browser/base/content/test/siteProtections/browser.ini @@ -1,6 +1,7 @@ [DEFAULT] support-files = head.js [browser_protections_UI.js] +skip-if = fission # Bug 1590696 [browser_protections_UI_milestones.js]
--- a/browser/base/content/test/siteProtections/browser_protections_UI.js +++ b/browser/base/content/test/siteProtections/browser_protections_UI.js @@ -1,46 +1,57 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ /* Basic UI tests for the protections panel */ +"use strict"; + +const TRACKING_PAGE = + "http://tracking.example.org/browser/browser/base/content/test/trackingUI/trackingPage.html"; + ChromeUtils.defineModuleGetter( this, "ContentBlockingAllowList", "resource://gre/modules/ContentBlockingAllowList.jsm" ); add_task(async function setup() { await SpecialPowers.pushPrefEnv({ set: [ // Set the auto hide timing to 100ms for blocking the test less. ["browser.protections_panel.toast.timeout", 100], // Hide protections cards so as not to trigger more async messaging // when landing on the page. ["browser.contentblocking.report.monitor.enabled", false], ["browser.contentblocking.report.lockwise.enabled", false], ["browser.contentblocking.report.proxy.enabled", false], + ["privacy.trackingprotection.enabled", true], ], }); let oldCanRecord = Services.telemetry.canRecordExtended; Services.telemetry.canRecordExtended = true; Services.telemetry.clearEvents(); registerCleanupFunction(() => { Services.telemetry.canRecordExtended = oldCanRecord; Services.telemetry.clearEvents(); }); }); add_task(async function testToggleSwitch() { let tab = await BrowserTestUtils.openNewForegroundTab( gBrowser, - "https://example.com" + TRACKING_PAGE ); + + await TestUtils.waitForCondition(() => { + return gProtectionsHandler._protectionsPopup.hasAttribute("blocking"); + }); + await openProtectionsPanel(); let events = Services.telemetry.snapshotEvents( Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS ).parent; let buttonEvents = events.filter( e => e[1] == "security.ui.protectionspopup" && e[2] == "open" &&
--- a/browser/base/content/test/siteProtections/browser_protections_UI_milestones.js +++ b/browser/base/content/test/siteProtections/browser_protections_UI_milestones.js @@ -4,16 +4,17 @@ add_task(async function setup() { await SpecialPowers.pushPrefEnv({ set: [ // Hide protections cards so as not to trigger more async messaging // when landing on the page. ["browser.contentblocking.report.monitor.enabled", false], ["browser.contentblocking.report.lockwise.enabled", false], ["browser.contentblocking.report.proxy.enabled", false], + ["browser.contentblocking.cfr-milestone.update-interval", 0], ], }); }); add_task(async function doTest() { // This also ensures that the DB tables have been initialized. await TrackingDBService.clearAll();
--- a/browser/base/content/test/tabs/browser.ini +++ b/browser/base/content/test/tabs/browser.ini @@ -64,18 +64,18 @@ skip-if = !e10s # Test only relevant for [browser_new_tab_insert_position.js] skip-if = (debug && os == 'linux' && bits == 32) #Bug 1455882, disabled on Linux32 for almost permafailing support-files = file_new_tab_page.html [browser_new_tab_in_privilegedabout_process_pref.js] skip-if = !e10s # Pref and test only relevant for e10s. [browser_privilegedmozilla_process_pref.js] skip-if = !e10s # Pref and test only relevant for e10s. [browser_new_web_tab_in_file_process_pref.js] -fail-if = fission # Expects http tab opened from file to be loaded in file content process skip-if = !e10s # Pref and test only relevant for e10s. + || fission # Expects http tab opened from file to be loaded in file content process. See bug 1594221 [browser_newwindow_tabstrip_overflow.js] [browser_open_newtab_start_observer_notification.js] [browser_opened_file_tab_navigated_to_web.js] [browser_overflowScroll.js] [browser_paste_event_at_middle_click_on_link.js] tags = clipboard support-files = file_anchor_elements.html [browser_pinnedTabs_clickOpen.js]
--- a/browser/base/content/test/trackingUI/browser_trackingUI_report_breakage.js +++ b/browser/base/content/test/trackingUI/browser_trackingUI_report_breakage.js @@ -59,16 +59,19 @@ add_task(async function setup() { ], }); }); add_task(async function testReportBreakageCancel() { Services.prefs.setBoolPref(TP_PREF, true); await BrowserTestUtils.withNewTab(TRACKING_PAGE, async function() { + await TestUtils.waitForCondition(() => + gProtectionsHandler._protectionsPopup.hasAttribute("blocking") + ); await openProtectionsPopup(); let siteNotWorkingButton = document.getElementById( "protections-popup-tp-switch-breakage-link" ); ok( BrowserTestUtils.is_visible(siteNotWorkingButton), "site not working button is visible" @@ -103,16 +106,41 @@ add_task(async function testReportBreaka await viewShown; ok(true, "Main view was shown"); }); Services.prefs.clearUserPref(TP_PREF); }); +add_task(async function testNoTracking() { + await BrowserTestUtils.withNewTab(BENIGN_PAGE, async function() { + await openProtectionsPopup(); + + let siteNotWorkingButton = document.getElementById( + "protections-popup-tp-switch-breakage-link" + ); + ok( + BrowserTestUtils.is_hidden(siteNotWorkingButton), + "site not working button is not visible" + ); + }); +}); + +add_task(async function testReportBreakageError() { + Services.prefs.setBoolPref(TP_PREF, true); + // Make sure that we correctly strip the query. + let url = TRACKING_PAGE + "?a=b&1=abc&unicode=🦊"; + await BrowserTestUtils.withNewTab(url, async function() { + await testReportBreakage(TRACKING_PAGE, "trackingprotection", true); + }); + + Services.prefs.clearUserPref(TP_PREF); +}); + add_task(async function testTP() { Services.prefs.setBoolPref(TP_PREF, true); // Make sure that we correctly strip the query. let url = TRACKING_PAGE + "?a=b&1=abc&unicode=🦊"; await BrowserTestUtils.withNewTab(url, async function() { await testReportBreakage(TRACKING_PAGE, "trackingprotection"); }); @@ -134,61 +162,68 @@ add_task(async function testCR() { }); add_task(async function testFP() { Services.prefs.setIntPref(CB_PREF, Ci.nsICookieService.BEHAVIOR_ACCEPT); Services.prefs.setBoolPref(FP_PREF, true); // Make sure that we correctly strip the query. let url = TRACKING_PAGE + "?a=b&1=abc&unicode=🦊"; await BrowserTestUtils.withNewTab(url, async function(browser) { + let promise = waitForContentBlockingEvent(); await SpecialPowers.spawn(browser, [], function() { content.postMessage("fingerprinting", "*"); }); + await promise; await testReportBreakage(TRACKING_PAGE, "fingerprinting"); }); Services.prefs.clearUserPref(FP_PREF); Services.prefs.clearUserPref(CB_PREF); }); add_task(async function testCM() { Services.prefs.setIntPref(CB_PREF, Ci.nsICookieService.BEHAVIOR_ACCEPT); Services.prefs.setBoolPref(CM_PREF, true); // Make sure that we correctly strip the query. let url = TRACKING_PAGE + "?a=b&1=abc&unicode=🦊"; await BrowserTestUtils.withNewTab(url, async function(browser) { + let promise = waitForContentBlockingEvent(); await SpecialPowers.spawn(browser, [], function() { content.postMessage("cryptomining", "*"); }); + await promise; await testReportBreakage(TRACKING_PAGE, "cryptomining"); }); Services.prefs.clearUserPref(CM_PREF); Services.prefs.clearUserPref(CB_PREF); }); -async function testReportBreakage(url, tags) { +async function testReportBreakage(url, tags, error = false) { // Setup a mock server for receiving breakage reports. let server = new HttpServer(); server.start(-1); let i = server.identity; let path = i.primaryScheme + "://" + i.primaryHost + ":" + i.primaryPort + "/"; Services.prefs.setStringPref(PREF_REPORT_BREAKAGE_URL, path); + await TestUtils.waitForCondition(() => + gProtectionsHandler._protectionsPopup.hasAttribute("blocking") + ); await openProtectionsPopup(); let siteNotWorkingButton = document.getElementById( "protections-popup-tp-switch-breakage-link" ); - await TestUtils.waitForCondition( - () => BrowserTestUtils.is_visible(siteNotWorkingButton), + ok( + BrowserTestUtils.is_visible(siteNotWorkingButton), "site not working button is visible" ); let siteNotWorkingView = document.getElementById( "protections-popup-siteNotWorkingView" ); let viewShown = BrowserTestUtils.waitForEvent( siteNotWorkingView, "ViewShown" @@ -276,22 +311,45 @@ async function testReportBreakage(url, t "This is a comment\r\n", 'Content-Disposition: form-data; name="labels"\r\n\r\n' + `${tags}\r\n`, "", ], "Should send the correct form data" ); + if (error) { + response.setStatusLine(request.httpVersion, 500, "Request failed"); + } else { + response.setStatusLine(request.httpVersion, 201, "Entry created"); + } + resolve(); }); comments.value = "This is a comment"; submitButton.click(); }); + let errorMessage = document.getElementById( + "protections-popup-sendReportView-report-error" + ); + if (error) { + await BrowserTestUtils.waitForCondition(() => + BrowserTestUtils.is_visible(errorMessage) + ); + is( + comments.value, + "This is a comment", + "Comment not cleared in case of an error" + ); + gProtectionsHandler._protectionsPopup.hidePopup(); + } else { + ok(BrowserTestUtils.is_hidden(errorMessage), "Error message not shown"); + } + await popuphidden; // Stop the server. await new Promise(r => server.stop(r)); Services.prefs.clearUserPref(PREF_REPORT_BREAKAGE_URL); }
--- a/browser/components/BrowserGlue.jsm +++ b/browser/components/BrowserGlue.jsm @@ -2108,17 +2108,25 @@ BrowserGlue.prototype = { "permissions.eventTelemetry.enabled", this._togglePermissionPromptTelemetry ); this._togglePermissionPromptTelemetry(); }); // Begin listening for incoming push messages. Services.tm.idleDispatchToMainThread(() => { - PushService.wrappedJSObject.ensureReady(); + try { + PushService.wrappedJSObject.ensureReady(); + } catch (ex) { + // NS_ERROR_NOT_AVAILABLE will get thrown for the PushService getter + // if the PushService is disabled. + if (ex.result != Cr.NS_ERROR_NOT_AVAILABLE) { + throw ex; + } + } }); Services.tm.idleDispatchToMainThread(() => { this._recordContentBlockingTelemetry(); }); Services.tm.idleDispatchToMainThread(() => { this._recordContentBlockerTelemetry();
--- a/browser/components/controlcenter/content/protectionsPanel.inc.xul +++ b/browser/components/controlcenter/content/protectionsPanel.inc.xul @@ -305,16 +305,19 @@ <vbox class="protections-popup-sendReportView-collection-section"> <label control="protections-popup-sendReportView-collection-url">&contentBlocking.breakageReportView.collection.url.label;</label> <html:input readonly="readonly" id="protections-popup-sendReportView-collection-url" aria-label="&contentBlocking.breakageReportView.collection.url.label;"/> </vbox> <vbox class="protections-popup-sendReportView-collection-section"> <label control="protections-popup-sendReportView-collection-comments">&contentBlocking.breakageReportView2.collection.comments.label;</label> <html:textarea id="protections-popup-sendReportView-collection-comments" aria-label="&contentBlocking.breakageReportView2.collection.comments.label;"/> </vbox> + <label id="protections-popup-sendReportView-report-error" + data-l10n-id="protections-panel-sendreportview-error" + hidden="true" role="alert"></label> </vbox> <vbox id="protections-popup-sendReportView-footer" class="panel-footer"> <button id="protections-popup-sendReportView-cancel" label="&contentBlocking.breakageReportView.cancel.label;" oncommand="gProtectionsHandler._protectionsPopupMultiView.goBack();"/> <button id="protections-popup-sendReportView-submit" default="true"
--- a/browser/components/extensions/test/browser/browser.ini +++ b/browser/components/extensions/test/browser/browser.ini @@ -1,14 +1,18 @@ [DEFAULT] tags = webextensions prefs = # We don't want to reset this at the end of the test, so that we don't have # to spawn a new extension child process for each test unit. dom.ipc.keepProcessesAlive.extension=1 + # With Fission enabled, this directory spawns many child processes, which + # somehow results in frequent leaks and shutdown hangs. Reuse the content + # processes to avoid this. + dom.ipc.keepProcessesAlive.webIsolated.perOrigin=1 dom.animations-api.core.enabled=true dom.animations-api.timelines.enabled=true plugin.load_flash_only=false support-files = head.js head_devtools.js file_inspectedwindow_reload_target.sjs silence.ogg
--- a/browser/components/newtab/content-src/asrouter/templates/FirstRun/FirstRun.jsx +++ b/browser/components/newtab/content-src/asrouter/templates/FirstRun/FirstRun.jsx @@ -17,22 +17,28 @@ export const FLUENT_FILES = [ "browser/newtab/onboarding.ftl", ]; export const helpers = { selectInterruptAndTriplets(message = {}, interruptCleared) { const hasInterrupt = interruptCleared === true ? false : Boolean(message.content); const hasTriplets = Boolean(message.bundle && message.bundle.length); + // Allow 1) falsy to not render a header 2) default welcome 3) custom header + const tripletsHeaderId = + message.tripletsHeaderId === undefined + ? "onboarding-welcome-header" + : message.tripletsHeaderId; const UTMTerm = message.utm_term || ""; return { hasTriplets, hasInterrupt, interrupt: hasInterrupt ? message : null, triplets: hasTriplets ? message.bundle : null, + tripletsHeaderId, UTMTerm, }; }, addFluent(document) { FLUENT_FILES.forEach(file => { const link = document.head.appendChild(document.createElement("link")); link.href = file; @@ -50,16 +56,17 @@ export class FirstRun extends React.Pure this.state = { prevMessage: undefined, hasInterrupt: false, hasTriplets: false, interrupt: undefined, triplets: undefined, + tripletsHeaderId: "", isInterruptVisible: false, isTripletsContainerVisible: false, isTripletsContentVisible: false, UTMTerm: "", flowParams: undefined, @@ -82,28 +89,30 @@ export class FirstRun extends React.Pure interruptCleared !== state.prevInterruptCleared || (message && message.id !== state.prevMessageId) ) { const { hasTriplets, hasInterrupt, interrupt, triplets, + tripletsHeaderId, UTMTerm, } = helpers.selectInterruptAndTriplets(message, interruptCleared); return { prevMessageId: message.id, prevInterruptCleared: interruptCleared, hasInterrupt, hasTriplets, interrupt, triplets, + tripletsHeaderId, isInterruptVisible: hasInterrupt, isTripletsContainerVisible: hasTriplets, isTripletsContentVisible: !(hasInterrupt || !hasTriplets), UTMTerm, }; } @@ -167,16 +176,17 @@ export class FirstRun extends React.Pure fxaEndpoint, dispatch, executeAction, } = props; const { interrupt, triplets, + tripletsHeaderId, isInterruptVisible, isTripletsContainerVisible, isTripletsContentVisible, hasTriplets, UTMTerm, flowParams, } = this.state; @@ -196,16 +206,17 @@ export class FirstRun extends React.Pure onDismiss={this.closeInterrupt} fxaEndpoint={fxaEndpoint} /> ) : null} {hasTriplets ? ( <Triplets document={props.document} cards={triplets} + headerId={tripletsHeaderId} showCardPanel={isTripletsContainerVisible} showContent={isTripletsContentVisible} hideContainer={this.closeTriplets} sendUserActionTelemetry={sendUserActionTelemetry} UTMTerm={`${UTMTerm}-card`} flowParams={flowParams} onAction={executeAction} />
--- a/browser/components/newtab/content-src/asrouter/templates/FirstRun/Triplets.jsx +++ b/browser/components/newtab/content-src/asrouter/templates/FirstRun/Triplets.jsx @@ -50,26 +50,27 @@ export class Triplets extends React.Pure message_id: cards.map(m => m.id).join(","), action: "onboarding_user_event", }); } render() { const { cards, + headerId, showCardPanel, showContent, sendUserActionTelemetry, } = this.props; return ( <div className={`trailheadCards ${showCardPanel ? "expanded" : "collapsed"}`} > <div className="trailheadCardsInner" aria-hidden={!showContent}> - <h1 data-l10n-id="onboarding-welcome-header" /> + {headerId && <h1 data-l10n-id={headerId} />} <div className={`trailheadCardGrid${showContent ? " show" : ""}`}> {cards.map(card => ( <OnboardingCard key={card.id} className="trailheadCard" sendUserActionTelemetry={sendUserActionTelemetry} onAction={this.onCardAction} UISurface="TRAILHEAD"
--- a/browser/components/newtab/data/content/activity-stream.bundle.js +++ b/browser/components/newtab/data/content/activity-stream.bundle.js @@ -3614,27 +3614,28 @@ class Triplets extends react__WEBPACK_IM message_id: cards.map(m => m.id).join(","), action: "onboarding_user_event" }); } render() { const { cards, + headerId, showCardPanel, showContent, sendUserActionTelemetry } = this.props; return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", { className: `trailheadCards ${showCardPanel ? "expanded" : "collapsed"}` }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", { className: "trailheadCardsInner", "aria-hidden": !showContent - }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("h1", { - "data-l10n-id": "onboarding-welcome-header" + }, headerId && react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("h1", { + "data-l10n-id": headerId }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", { className: `trailheadCardGrid${showContent ? " show" : ""}` }, cards.map(card => react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_templates_OnboardingMessage_OnboardingMessage__WEBPACK_IMPORTED_MODULE_1__["OnboardingCard"], _extends({ key: card.id, className: "trailheadCard", sendUserActionTelemetry: sendUserActionTelemetry, onAction: this.onCardAction, UISurface: "TRAILHEAD" @@ -14692,22 +14693,24 @@ var addUtmParams = __webpack_require__(2 // Note: should match the transition time on .trailheadCards in _Trailhead.scss const TRANSITION_LENGTH = 500; const FLUENT_FILES = ["branding/brand.ftl", "browser/branding/brandings.ftl", "browser/branding/sync-brand.ftl", "browser/newtab/onboarding.ftl"]; const helpers = { selectInterruptAndTriplets(message = {}, interruptCleared) { const hasInterrupt = interruptCleared === true ? false : Boolean(message.content); const hasTriplets = Boolean(message.bundle && message.bundle.length); + const tripletsHeaderId = message.tripletsHeaderId === undefined ? "onboarding-welcome-header" : message.tripletsHeaderId; const UTMTerm = message.utm_term || ""; return { hasTriplets, hasInterrupt, interrupt: hasInterrupt ? message : null, triplets: hasTriplets ? message.bundle : null, + tripletsHeaderId, UTMTerm }; }, addFluent(document) { FLUENT_FILES.forEach(file => { const link = document.head.appendChild(document.createElement("link")); link.href = file; @@ -14721,16 +14724,17 @@ class FirstRun_FirstRun extends external super(props); this.didLoadFlowParams = false; this.state = { prevMessage: undefined, hasInterrupt: false, hasTriplets: false, interrupt: undefined, triplets: undefined, + tripletsHeaderId: "", isInterruptVisible: false, isTripletsContainerVisible: false, isTripletsContentVisible: false, UTMTerm: "", flowParams: undefined }; this.closeInterrupt = this.closeInterrupt.bind(this); this.closeTriplets = this.closeTriplets.bind(this); @@ -14749,25 +14753,27 @@ class FirstRun_FirstRun extends external } = props; if (interruptCleared !== state.prevInterruptCleared || message && message.id !== state.prevMessageId) { const { hasTriplets, hasInterrupt, interrupt, triplets, + tripletsHeaderId, UTMTerm } = helpers.selectInterruptAndTriplets(message, interruptCleared); return { prevMessageId: message.id, prevInterruptCleared: interruptCleared, hasInterrupt, hasTriplets, interrupt, triplets, + tripletsHeaderId, isInterruptVisible: hasInterrupt, isTripletsContainerVisible: hasTriplets, isTripletsContentVisible: !(hasInterrupt || !hasTriplets), UTMTerm }; } return null; @@ -14839,16 +14845,17 @@ class FirstRun_FirstRun extends external sendUserActionTelemetry, fxaEndpoint, dispatch, executeAction } = props; const { interrupt, triplets, + tripletsHeaderId, isInterruptVisible, isTripletsContainerVisible, isTripletsContentVisible, hasTriplets, UTMTerm, flowParams } = this.state; return external_React_default.a.createElement(external_React_default.a.Fragment, null, isInterruptVisible ? external_React_default.a.createElement(Interrupt_Interrupt, { @@ -14861,16 +14868,17 @@ class FirstRun_FirstRun extends external executeAction: executeAction, dispatch: dispatch, flowParams: flowParams, onDismiss: this.closeInterrupt, fxaEndpoint: fxaEndpoint }) : null, hasTriplets ? external_React_default.a.createElement(Triplets["Triplets"], { document: props.document, cards: triplets, + headerId: tripletsHeaderId, showCardPanel: isTripletsContainerVisible, showContent: isTripletsContentVisible, hideContainer: this.closeTriplets, sendUserActionTelemetry: sendUserActionTelemetry, UTMTerm: `${UTMTerm}-card`, flowParams: flowParams, onAction: executeAction }) : null);
--- a/browser/components/newtab/lib/ASRouter.jsm +++ b/browser/components/newtab/lib/ASRouter.jsm @@ -1976,17 +1976,16 @@ class _ASRouter { lastMessageId: message ? message.id : null, messages: message ? state.messages.filter(m => m.id !== message.id) : state.messages, })); } else { // On new tab, send cards if they match; othwerise send a snippet message = await this.handleMessageRequest({ - provider: "onboarding", template: "extended_triplets", }); // Set up the experiment for extended triplets. It's done here because we // only want to enroll users (for both control and holdback) if they meet // the targeting criteria. if (message) { await this.setupExtendedTriplets();
--- a/browser/components/newtab/test/unit/asrouter/ASRouter.test.js +++ b/browser/components/newtab/test/unit/asrouter/ASRouter.test.js @@ -1383,17 +1383,16 @@ describe("ASRouter", () => { }); it("should handle onboarding message provider", async () => { const handleMessageRequestStub = sandbox.stub( Router, "handleMessageRequest" ); handleMessageRequestStub .withArgs({ - provider: "onboarding", template: "extended_triplets", }) .resolves({ id: "foo" }); const spy = sandbox.spy(Router, "setupExtendedTriplets"); const msg = fakeAsyncMessage({ type: "NEWTAB_MESSAGE_REQUEST", data: {}, }); @@ -1404,57 +1403,53 @@ describe("ASRouter", () => { it("should fallback to snippets if one was assigned to the holdback experiment", async () => { sandbox.stub(global.Sampling, "ratioSample").resolves(1); // 1 = holdback branch const handleMessageRequestStub = sandbox.stub( Router, "handleMessageRequest" ); handleMessageRequestStub .withArgs({ - provider: "onboarding", template: "extended_triplets", }) .resolves({ id: "foo" }); const msg = fakeAsyncMessage({ type: "NEWTAB_MESSAGE_REQUEST", data: {}, }); await Router.onMessage(msg); assert.calledTwice(handleMessageRequestStub); assert.calledWithExactly(handleMessageRequestStub, { - provider: "onboarding", template: "extended_triplets", }); assert.calledWithExactly(handleMessageRequestStub, { provider: "snippets", }); }); it("should fallback to snippets if onboarding message provider returned none", async () => { const handleMessageRequestStub = sandbox.stub( Router, "handleMessageRequest" ); handleMessageRequestStub .withArgs({ - provider: "onboarding", template: "extended_triplets", }) .resolves(null); const spy = sandbox.spy(Router, "setupExtendedTriplets"); const msg = fakeAsyncMessage({ type: "NEWTAB_MESSAGE_REQUEST", data: {}, }); await Router.onMessage(msg); assert.notCalled(spy); assert.calledTwice(handleMessageRequestStub); assert.calledWithExactly(handleMessageRequestStub, { - provider: "onboarding", template: "extended_triplets", }); assert.calledWithExactly(handleMessageRequestStub, { provider: "snippets", }); }); });
--- a/browser/components/privatebrowsing/test/browser/browser.ini +++ b/browser/components/privatebrowsing/test/browser/browser.ini @@ -24,17 +24,16 @@ support-files = skip-if = fission || verify tags = trackingprotection [browser_privatebrowsing_about_search_banner.js] [browser_privatebrowsing_aboutSessionRestore.js] [browser_privatebrowsing_cache.js] [browser_privatebrowsing_certexceptionsui.js] [browser_privatebrowsing_concurrent.js] [browser_privatebrowsing_context_and_chromeFlags.js] -skip-if = fission [browser_privatebrowsing_crh.js] [browser_privatebrowsing_downloadLastDir.js] skip-if = verify [browser_privatebrowsing_downloadLastDir_c.js] [browser_privatebrowsing_downloadLastDir_toggle.js] [browser_privatebrowsing_favicon.js] [browser_privatebrowsing_geoprompt.js] tags = geolocation
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_context_and_chromeFlags.js +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_context_and_chromeFlags.js @@ -49,17 +49,19 @@ function assertWindowIsPrivate(win) { * window. */ add_task(async function test_context_and_chromeFlags() { let win = await BrowserTestUtils.openNewBrowserWindow({ private: true }); await assertWindowIsPrivate(win); let browser = win.gBrowser.selectedBrowser; - let newWinPromise = BrowserTestUtils.waitForNewWindow(); + let newWinPromise = BrowserTestUtils.waitForNewWindow({ + url: "http://example.com/", + }); await ContentTask.spawn(browser, null, async function() { content.open("http://example.com", "_blank", "width=100,height=100"); }); let win2 = await newWinPromise; await assertWindowIsPrivate(win2); await BrowserTestUtils.closeWindow(win2);
--- a/browser/components/urlbar/tests/browser/browser.ini +++ b/browser/components/urlbar/tests/browser/browser.ini @@ -44,17 +44,16 @@ skip-if = verify && os == 'linux' # Bug [browser_doubleClickSelectsAll.js] [browser_downArrowKeySearch.js] [browser_dragdropURL.js] [browser_dropmarker.js] [browser_ime_composition.js] [browser_inputHistory.js] [browser_inputHistory_emptystring.js] [browser_keepStateAcrossTabSwitches.js] -skip-if = fission [browser_keywordBookmarklets.js] [browser_keyword_override.js] [browser_keywordSearch.js] support-files = searchSuggestionEngine.xml searchSuggestionEngine.sjs [browser_keywordSearch_postData.js] support-files = @@ -64,18 +63,16 @@ support-files = [browser_keyword.js] support-files = print_postdata.sjs searchSuggestionEngine.xml searchSuggestionEngine.sjs [browser_locationBarCommand.js] skip-if = (os == 'mac' && os_version == '10.14') # bug 1554807 [browser_locationBarExternalLoad.js] -[browser_moz_action_link.js] -skip-if = fission # Timeouts [browser_new_tab_urlbar_reset.js] [browser_openViewOnFocus.js] [browser_pasteAndGo.js] tags = clipboard [browser_percent_encoded.js] [browser_populateAfterPushState.js] [browser_primary_selection_safe_on_new_tab.js] [browser_privateBrowsingWindowChange.js]
--- a/browser/components/urlbar/tests/browser/browser_keepStateAcrossTabSwitches.js +++ b/browser/components/urlbar/tests/browser/browser_keepStateAcrossTabSwitches.js @@ -2,48 +2,47 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; /** * Verify user typed text remains in the URL bar when tab switching, even when * loads fail. */ -add_task(async function() { +add_task(async function validURL() { let input = "i-definitely-dont-exist.example.com"; let tab = await BrowserTestUtils.openNewForegroundTab( gBrowser, - "about:blank", - false + "http://example.com/" ); let browser = tab.linkedBrowser; // Note: Waiting on content document not being hidden because new tab pages can be preloaded, // in which case no load events fire. await ContentTask.spawn(browser, null, async () => { await ContentTaskUtils.waitForCondition(() => { return content.document && !content.document.hidden; }); }); - let errorPageLoaded = BrowserTestUtils.waitForErrorPage(tab.linkedBrowser); + let errorPageLoaded = BrowserTestUtils.waitForErrorPage(browser); gURLBar.value = input; gURLBar.select(); EventUtils.sendKey("return"); await errorPageLoaded; is(gURLBar.value, input, "Text is still in URL bar"); await BrowserTestUtils.switchTab(gBrowser, tab.previousElementSibling); await BrowserTestUtils.switchTab(gBrowser, tab); is(gURLBar.value, input, "Text is still in URL bar after tab switch"); BrowserTestUtils.removeTab(tab); }); /** * Invalid URIs fail differently (that is, immediately, in the loadURI call) * if keyword searches are turned off. Test that this works, too. */ -add_task(async function() { +add_task(async function invalidURL() { let input = "To be or not to be-that is the question"; await SpecialPowers.pushPrefEnv({ set: [["keyword.enabled", false]] }); let tab = await BrowserTestUtils.openNewForegroundTab( gBrowser, "about:blank", false ); let browser = tab.linkedBrowser;
deleted file mode 100644 --- a/browser/components/urlbar/tests/browser/browser_moz_action_link.js +++ /dev/null @@ -1,40 +0,0 @@ -"use strict"; - -const kURIs = ["moz-action:foo,", "moz-action:foo"]; - -add_task(async function() { - for (let uri of kURIs) { - let dataURI = `data:text/html,<a id=a href="${uri}" target=_blank rel="opener">Link</a>`; - let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, dataURI); - - let tabSwitchPromise = BrowserTestUtils.switchTab(gBrowser, function() {}); - await ContentTask.spawn(tab.linkedBrowser, null, async function() { - content.document.getElementById("a").click(); - }); - await tabSwitchPromise; - isnot(gBrowser.selectedTab, tab, "Switched to new tab!"); - is( - gURLBar.value, - "about:blank", - "URL bar should be displaying about:blank" - ); - let newTab = gBrowser.selectedTab; - await BrowserTestUtils.switchTab(gBrowser, tab); - await BrowserTestUtils.switchTab(gBrowser, newTab); - is(gBrowser.selectedTab, newTab, "Switched to new tab again!"); - is( - gURLBar.value, - "about:blank", - "URL bar should be displaying about:blank after tab switch" - ); - // Finally, check that directly setting it produces the right results, too: - URLBarSetURI(makeURI(uri)); - is( - gURLBar.value, - "about:blank", - "URL bar should still be displaying about:blank" - ); - BrowserTestUtils.removeTab(newTab); - BrowserTestUtils.removeTab(tab); - } -});
--- a/browser/components/urlbar/tests/browser/browser_urlbarDecode.js +++ b/browser/components/urlbar/tests/browser/browser_urlbarDecode.js @@ -49,18 +49,17 @@ add_task(function losslessDecode() { add_task(async function actionURILosslessDecode() { let urlNoScheme = "example.com/\u30a2\u30a4\u30a6\u30a8\u30aa"; let url = "http://" + urlNoScheme; await promiseAutocompleteResultPopup(url); // At this point the heuristic result is selected but the urlbar's value is // simply `url`. Key down and back around until the heuristic result is - // selected again, and at that point the urlbar's value should be a visiturl - // moz-action. + // selected again. do { EventUtils.synthesizeKey("KEY_ArrowDown"); } while (UrlbarTestUtils.getSelectedRowIndex(window) != 0); let result = await UrlbarTestUtils.getDetailsOfResultAt(window, 0); Assert.equal( result.type,
--- a/browser/locales/en-US/browser/preferences/preferences.ftl +++ b/browser/locales/en-US/browser/preferences/preferences.ftl @@ -863,32 +863,36 @@ sync-device-name-save = .accesskey = v sync-connect-another-device = Connect another device ## Privacy Section privacy-header = Browser Privacy -## Privacy Section - Forms +## Privacy Section - Logins and Passwords logins-header = Logins and Passwords + +# Checkbox to control whether UI is shown to users to save or fill logins/passwords. forms-ask-to-save-logins = .label = Ask to save logins and passwords for websites .accesskey = r forms-exceptions = .label = Exceptions… .accesskey = x forms-generate-passwords = .label = Suggest and generate strong passwords .accesskey = u forms-breach-alerts = .label = Show alerts about passwords for breached websites .accesskey = b forms-breach-alerts-learn-more-link = Learn more + +# Checkbox which controls filling saved logins into fields automatically when they appear, in some cases without user interaction. forms-fill-logins-and-passwords = .label = Autofill logins and passwords .accesskey = i forms-saved-logins = .label = Saved Logins… .accesskey = L forms-master-pw-use = .label = Use a master password
new file mode 100644 --- /dev/null +++ b/browser/locales/en-US/browser/protectionsPanel.ftl @@ -0,0 +1,5 @@ +# 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/. + +protections-panel-sendreportview-error = There was an error sending the report. Please try again later.
--- a/browser/locales/en-US/chrome/browser/browser.properties +++ b/browser/locales/en-US/chrome/browser/browser.properties @@ -1015,13 +1015,14 @@ storageAccess.description.learnmore = th confirmationHint.sendToDevice.label = Sent! confirmationHint.copyURL.label = Copied to clipboard! confirmationHint.pageBookmarked.label = Saved to Library! confirmationHint.addSearchEngine.label = Search engine added! confirmationHint.pinTab.label = Pinned! confirmationHint.pinTab.description = Right-click the tab to unpin it. confirmationHint.passwordSaved.label = Password saved! +confirmationHint.breakageReport.label = Report sent. Thank you! # LOCALIZATION NOTE (livebookmarkMigration.title): # Used by the export of user's live bookmarks to an OPML file as a title for the file. # %S will be replaced with brandShortName livebookmarkMigration.title = %S Live Bookmarks
--- a/browser/themes/shared/controlcenter/panel.inc.css +++ b/browser/themes/shared/controlcenter/panel.inc.css @@ -474,16 +474,21 @@ description#identity-popup-content-verif #protections-popup-sendReportView-collection-comments { height: 120px; } #protections-popup-sendReportView label { margin-inline-start: 0; } +#protections-popup-sendReportView-report-error { + margin-bottom: 24px; + color: #d74345; +} + .protections-popup-category { /* Overwrite toolbarbutton styles */ -moz-appearance: none; margin: 0; padding-inline-start: 0; } .protections-popup-category:-moz-focusring,
--- a/browser/themes/shared/urlbar-autocomplete.inc.css +++ b/browser/themes/shared/urlbar-autocomplete.inc.css @@ -124,19 +124,24 @@ white-space: nowrap; } .urlbarView:not(.megabar) .urlbarView-results { padding-inline: @urlbarViewPadding@; } .urlbarView-row { - border-radius: 2px; fill: currentColor; fill-opacity: .6; + padding-block: 3px; +} + +.urlbarView:not(.megabar) .urlbarView-row, +.urlbarView.megabar .urlbarView-row-inner { + border-radius: 2px; padding-block: 6px; padding-inline-start: calc(@urlbarViewItemPaddingStart@); } .urlbarView:not(.megabar) .urlbarView-row { padding-inline-start: calc(var(--item-padding-start, calc(5px + @urlbarViewFaviconOffset@)) - @urlbarViewFaviconOffset@); padding-inline-end: var(--item-padding-end, 5px); } @@ -161,21 +166,23 @@ mask-image: linear-gradient(to right, transparent, black 2em); } .urlbarView-title[isurl]:-moz-locale-dir(rtl), .urlbarView-url:-moz-locale-dir(rtl) { direction: ltr !important; } -.urlbarView-row:not([type=tip]):hover { +.urlbarView:not(.megabar) .urlbarView-row:not([type=tip]):hover, +.urlbarView.megabar .urlbarView-row:not([type=tip]):hover > .urlbarView-row-inner { background: var(--arrowpanel-dimmed); } -.urlbarView-row:not([type=tip])[selected] { +.urlbarView:not(.megabar) .urlbarView-row:not([type=tip])[selected], +.urlbarView.megabar .urlbarView-row:not([type=tip])[selected] > .urlbarView-row-inner { background: var(--autocomplete-popup-highlight-background); color: var(--autocomplete-popup-highlight-color); fill-opacity: 1; } .urlbarView-type-icon, .urlbarView-favicon { min-width: 16px;
--- a/build/unix/mozconfig.unix +++ b/build/unix/mozconfig.unix @@ -8,17 +8,22 @@ if [ -n "$FORCE_GCC" ]; then # We want to make sure we use binutils and other binaries in the tooltool # package. mk_add_options "export PATH=$MOZ_FETCHES_DIR/gcc/bin:$PATH" ac_add_options --with-clang-path=$MOZ_FETCHES_DIR/clang/bin/clang else CC="$MOZ_FETCHES_DIR/clang/bin/clang" CXX="$MOZ_FETCHES_DIR/clang/bin/clang++" - export ENABLE_CLANG_PLUGIN=1 + + # For some builds we don't want to have Clang based static-analysis activated + if [ -z "$DISABLE_CLANG_PLUGIN" ]; then + export ENABLE_CLANG_PLUGIN=1 + fi + case "$PERFHERDER_EXTRA_OPTIONS" in base-toolchains*) # Clang versions < 7.0 don't support the -fcrash-diagnostics-dir flag. ;; *) export CFLAGS="$CFLAGS -fcrash-diagnostics-dir=${UPLOAD_PATH}" export CXXFLAGS="$CXXFLAGS -fcrash-diagnostics-dir=${UPLOAD_PATH}" ;;
--- a/devtools/client/debugger/src/actions/navigation.js +++ b/devtools/client/debugger/src/actions/navigation.js @@ -73,12 +73,13 @@ export function connect( }; } /** * @memberof actions/navigation * @static */ export function navigated() { - return async function({ panel }: ThunkArgs) { + return async function({ dispatch, panel }: ThunkArgs) { + await dispatch(updateThreads()); panel.emit("reloaded"); }; }
--- a/devtools/client/debugger/src/actions/threads.js +++ b/devtools/client/debugger/src/actions/threads.js @@ -3,18 +3,24 @@ * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ // @flow import { differenceBy } from "lodash"; import type { Action, ThunkArgs } from "./types"; import type { ThreadType } from "../types"; import { removeSourceActors } from "./source-actors"; +import { newGeneratedSources } from "./sources"; -import { getContext, getThreads, getSourceActorsForThread } from "../selectors"; +import { + getContext, + getAllThreads, + getThreads, + getSourceActorsForThread, +} from "../selectors"; export function updateThreads(type: ?ThreadType) { return async function({ dispatch, getState, client }: ThunkArgs) { const cx = getContext(getState()); const threads = await client.fetchThreads(type); const currentThreads = getThreads(getState()); @@ -31,11 +37,32 @@ export function updateThreads(type: ?Thr type: "REMOVE_THREADS", cx, threads: removedThreads.map(t => t.actor), }: Action) ); } if (addedThreads.length > 0) { dispatch(({ type: "INSERT_THREADS", cx, threads: addedThreads }: Action)); + + // Fetch the sources and install breakpoints on any new workers. + // NOTE: This runs in the background and fails quietly because it is + // pretty easy for sources to throw during the fetch if their thread + // shuts down, which would cause test failures. + for (const thread of addedThreads) { + client + .fetchThreadSources(thread.actor) + .then(sources => dispatch(newGeneratedSources(sources))) + .catch(e => console.error(e)); + } } }; } + +export function ensureHasThread(thread: string) { + return async function({ dispatch, getState, client }: ThunkArgs) { + const currentThreads = getAllThreads(getState()); + if (!currentThreads.some(t => t.actor == thread)) { + await dispatch(updateThreads("worker")); + await dispatch(updateThreads("contentProcess")); + } + }; +}
--- a/devtools/client/debugger/src/client/firefox/commands.js +++ b/devtools/client/debugger/src/client/firefox/commands.js @@ -310,20 +310,22 @@ function autocomplete( cursor, result => resolve(result), frameId ); }); } function navigate(url: string): Promise<*> { + targets = { worker: {}, contentProcess: {} }; return currentTarget.navigateTo({ url }); } function reload(): Promise<*> { + targets = { worker: {}, contentProcess: {} }; return currentTarget.reload(); } function getProperties(thread: string, grip: Grip): Promise<*> { const objClient = lookupThreadFront(thread).pauseGrip(grip); return objClient.getPrototypeAndProperties().then(resp => { const { ownProperties, safeGetterValues } = resp; @@ -442,16 +444,22 @@ function getAllThreadFronts() { async function fetchSources(): Promise<Array<GeneratedSourceData>> { let sources = []; for (const threadFront of getAllThreadFronts()) { sources = sources.concat(await getSources(threadFront)); } return sources; } +async function fetchThreadSources( + thread: string +): Promise<Array<GeneratedSourceData>> { + return getSources(lookupThreadFront(thread)); +} + // Check if any of the targets were paused before we opened // the debugger. If one is paused. Fake a `pause` RDP event // by directly calling the client event listener. async function checkIfAlreadyPaused() { for (const threadFront of getAllThreadFronts()) { const pausedPacket = threadFront.getLastPausePacket(); if (pausedPacket) { clientEvents.paused(threadFront, pausedPacket); @@ -478,36 +486,23 @@ async function fetchThreads(type: ?Threa async function updateThreads(type: ThreadType) { const options = { breakpoints, eventBreakpoints, observeAsmJS: true, }; - const oldActors = Object.keys(targets[type]); - await updateTargets(type, { currentTarget, debuggerClient, targets, options, }); - // Fetch the sources and install breakpoints on any new workers. - // NOTE: This runs in the background and fails quitely because it is - // pretty easy for sources to throw during the fetch if their thread - // shuts down, which would cause test failures. - for (const entry of Object.entries(targets[type])) { - const [actor, { threadFront }] = (entry: any); - if (!oldActors.includes(actor)) { - getSources(threadFront).catch(e => console.error(e)); - } - } - return Object.entries(targets[type]).map(([actor, target]) => createThread((actor: any), (target: any)) ); } function getMainThread() { return currentThreadFront.actor; } @@ -591,16 +586,17 @@ const clientCommands = { evaluateExpressions, navigate, reload, getProperties, getFrameScopes, pauseOnExceptions, toggleEventLogging, fetchSources, + fetchThreadSources, checkIfAlreadyPaused, registerSourceActor, fetchThreads, getMainThread, sendPacket, setSkipPausing, setEventListenerBreakpoints, getEventListenerBreakpointTypes,
--- a/devtools/client/debugger/src/client/firefox/events.js +++ b/devtools/client/debugger/src/client/firefox/events.js @@ -11,16 +11,22 @@ import type { Actions, Target, DebuggerClient, } from "./types"; import { createPause, prepareSourcePayload } from "./create"; import sourceQueue from "../../utils/source-queue"; import { recordEvent } from "../../utils/telemetry"; +import { features } from "../../utils/prefs"; + +const { + WorkersListener, + // $FlowIgnore +} = require("devtools/client/shared/workers-listener.js"); const CALL_STACK_PAGE_SIZE = 1000; type Dependencies = { threadFront: ThreadFront, tabTarget: Target, actions: Actions, debuggerClient: DebuggerClient, @@ -40,19 +46,31 @@ function setupEvents(dependencies: Depen actions = dependencies.actions; sourceQueue.initialize(actions); addThreadEventListeners(threadFront); tabTarget.on("workerListChanged", () => threadListChanged("worker")); debuggerClient.mainRoot.on("processListChanged", () => threadListChanged("contentProcess") ); + + // If we are attaching to service workers we need to listen to worker changes + // everywhere in the browser. + if (features.windowlessServiceWorkers) { + const workersListener = new WorkersListener(debuggerClient.mainRoot); + workersListener.addListener(() => threadListChanged("worker")); + } } async function paused(threadFront: ThreadFront, packet: PausedPacket) { + // When reloading we might get pauses from threads before they have been + // added to the store. Ensure the pause won't be processed until we've + // finished adding the thread. + await actions.ensureHasThread(threadFront.actor); + // If paused by an explicit interrupt, which are generated by the // slow script dialog and internal events such as setting // breakpoints, ignore the event. const { why } = packet; if (why.type === "interrupted" && !packet.why.onNext) { isInterrupted = true; return; }
--- a/devtools/client/debugger/src/client/firefox/targets.js +++ b/devtools/client/debugger/src/client/firefox/targets.js @@ -1,16 +1,17 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ // @flow import { addThreadEventListeners } from "./events"; -import { prefs } from "../../utils/prefs"; +import { prefs, features } from "../../utils/prefs"; +import { sameOrigin } from "../../utils/url"; import type { DebuggerClient, Target } from "./types"; import type { ThreadType } from "../../types"; // $FlowIgnore const { defaultThreadOptions } = require("devtools/client/shared/thread-utils"); type Args = { currentTarget: Target, @@ -59,22 +60,35 @@ async function attachTargets(type, targe } catch (e) { // If any of the workers have terminated since the list command initiated // then we will get errors. Ignore these. } } } export async function updateWorkerTargets(type: ThreadType, args: Args) { - const { currentTarget } = args; + const { currentTarget, debuggerClient } = args; if (!currentTarget.isBrowsingContext || currentTarget.isContentProcess) { return; } const { workers } = await currentTarget.listWorkers(); + + if (features.windowlessServiceWorkers && currentTarget.url) { + const { service } = await debuggerClient.mainRoot.listAllWorkers(); + for (const { active, id, url } of service) { + // Attach to any service workers that are same-origin with our target. + // For now, ignore service workers associated with cross-origin iframes. + if (active && sameOrigin(url, currentTarget.url)) { + const workerTarget = await debuggerClient.mainRoot.getWorker(id); + workers.push(workerTarget); + } + } + } + await attachTargets(type, workers, args); } export async function updateProcessTargets(type: ThreadType, args: Args) { const { currentTarget, debuggerClient } = args; if (!prefs.fission || !currentTarget.chrome || currentTarget.isAddon) { return; }
--- a/devtools/client/debugger/src/client/firefox/types.js +++ b/devtools/client/debugger/src/client/firefox/types.js @@ -181,16 +181,17 @@ export type TabPayload = { * @static */ export type Actions = { paused: Pause => void, resumed: ActorId => void, newQueuedSources: (QueuedSourceData[]) => void, fetchEventListeners: () => void, updateThreads: typeof actions.updateThreads, + ensureHasThread: typeof actions.ensureHasThread, setFramePositions: typeof actions.setFramePositions, }; type ConsoleClient = { evaluateJS: ( script: Script, func: Function, params?: { frameActor: ?FrameId } @@ -251,16 +252,18 @@ export type DebuggerClient = { _activeRequests: { get: any => any, delete: any => void, }, mainRoot: { traits: any, getFront: string => Promise<*>, listProcesses: () => Promise<{ processes: ProcessDescriptor }>, + listAllWorkers: () => Promise<*>, + getWorker: any => Promise<*>, on: (string, Function) => void, }, connect: () => Promise<*>, request: (packet: Object) => Promise<*>, attachConsole: (actor: String, listeners: Array<*>) => Promise<*>, createObjectFront: (grip: Grip) => ObjectFront, release: (actor: String) => {}, getFrontByID: (actor: String) => { release: () => Promise<*> },
--- a/devtools/client/debugger/src/utils/prefs.js +++ b/devtools/client/debugger/src/utils/prefs.js @@ -138,16 +138,17 @@ export const features = new PrefsHelper( xhrBreakpoints: ["Bool", "xhr-breakpoints"], originalBlackbox: ["Bool", "original-blackbox"], eventListenersBreakpoints: ["Bool", "event-listeners-breakpoints"], domMutationBreakpoints: ["Bool", "dom-mutation-breakpoints"], logPoints: ["Bool", "log-points"], showOverlay: ["Bool", "overlay"], inlinePreview: ["Bool", "inline-preview"], watchpoints: ["Bool", "watchpoints"], + windowlessServiceWorkers: ["Bool", "windowless-service-workers"], }); export const asyncStore = asyncStoreHelper("debugger", { pendingBreakpoints: ["pending-breakpoints", {}], tabs: ["tabs", []], xhrBreakpoints: ["xhr-breakpoints", []], eventListenerBreakpoints: ["event-listener-breakpoints", undefined], });
--- a/devtools/client/debugger/src/utils/url.js +++ b/devtools/client/debugger/src/utils/url.js @@ -32,8 +32,12 @@ export const parse = memoize(function pa // If we're given simply a filename... if (url) { return { ...defaultUrl, path: url, pathname: url }; } return defaultUrl; } }); + +export function sameOrigin(firstUrl: string, secondUrl: string) { + return parse(firstUrl).origin == parse(secondUrl).origin; +}
--- a/devtools/client/debugger/test/mochitest/browser.ini +++ b/devtools/client/debugger/test/mochitest/browser.ini @@ -154,16 +154,17 @@ skip-if = os == "win" [browser_dbg-tabs-without-urls.js] [browser_dbg-toggling-tools.js] [browser_dbg-react-app.js] skip-if = os == "win" [browser_dbg-wasm-sourcemaps.js] [browser_dbg-windowless-workers.js] [browser_dbg-windowless-workers-early-breakpoint.js] [browser_dbg-worker-exception.js] +[browser_dbg-windowless-service-workers.js] [browser_dbg-worker-scopes.js] skip-if = (os == 'linux' && debug) || (os == 'linux' && asan) || ccov #Bug 1456013, Bug 1559547 [browser_dbg-event-handler.js] [browser_dbg-event-breakpoints.js] [browser_dbg-eval-throw.js] [browser_dbg-sourceURL-breakpoint.js] [browser_dbg-old-breakpoint.js] [browser_dbg-idb-run-to-completion.js]
--- a/devtools/client/debugger/test/mochitest/browser_dbg-bfcache.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg-bfcache.js @@ -1,12 +1,14 @@ /* 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/>. */ +PromiseTestUtils.whitelistRejectionsGlobally(/Connection closed/); + // Test that sources appear in the debugger when navigating using the BFCache. add_task(async function() { const dbg = await initDebugger("doc-bfcache1.html"); await navigate(dbg, "doc-bfcache2.html", "doc-bfcache2.html"); invokeInTab("goBack"); await waitForSources(dbg, "doc-bfcache1.html"); invokeInTab("goForward"); await waitForSources(dbg, "doc-bfcache2.html");
new file mode 100644 --- /dev/null +++ b/devtools/client/debugger/test/mochitest/browser_dbg-windowless-service-workers.js @@ -0,0 +1,68 @@ +/* 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/>. */ + +// Test that we can detect a new service worker and hit breakpoints that we've +// set in it. +add_task(async function() { + await pushPref("devtools.debugger.features.windowless-service-workers", true); + await pushPref("devtools.debugger.workers-visible", true); + await pushPref("dom.serviceWorkers.enabled", true); + await pushPref("dom.serviceWorkers.testing.enabled", true); + + let dbg = await initDebugger("doc-service-workers.html"); + + invokeInTab("registerWorker"); + + await waitForSource(dbg, "service-worker.js"); + const workerSource = findSource(dbg, "service-worker.js"); + + await addBreakpoint(dbg, "service-worker.js", 14); + + invokeInTab("fetchFromWorker"); + + await waitForPaused(dbg); + assertPausedAtSourceAndLine(dbg, workerSource.id, 14); + + await dbg.actions.removeAllBreakpoints(getContext(dbg)); + + await resume(dbg); + + // Leave the worker registration in place for the next task. + + // Set startup breakpoint for the next test. + //await addBreakpoint(dbg, "service-worker.js", 6); +}); + +async function checkWorkerThreads(dbg, count) { + await waitUntil(() => dbg.selectors.getThreads().length == count); + ok(true, `Have ${count} threads`); +} + +// Test that service workers remain after reloading. +add_task(async function() { + const toolbox = await openNewTabAndToolbox(EXAMPLE_URL + "doc-service-workers.html", "jsdebugger"); + const dbg = createDebuggerContext(toolbox); + + await checkWorkerThreads(dbg, 1); + + await reload(dbg); + + await waitForSource(dbg, "service-worker.js"); + const workerSource = findSource(dbg, "service-worker.js"); + + await addBreakpoint(dbg, "service-worker.js", 14); + + invokeInTab("fetchFromWorker"); + + await waitForPaused(dbg); + assertPausedAtSourceAndLine(dbg, workerSource.id, 14); + await checkWorkerThreads(dbg, 1); + + await resume(dbg); + + invokeInTab("unregisterWorker"); + + await dbg.actions.removeAllBreakpoints(getContext(dbg)); + await checkWorkerThreads(dbg, 0); +});
new file mode 100644 --- /dev/null +++ b/devtools/client/debugger/test/mochitest/examples/doc-service-workers.html @@ -0,0 +1,32 @@ +<script> +async function registerWorker() { + const sw = navigator.serviceWorker; + const swr = await sw.register("service-worker.js", { scope: "" }); + dump(`Registered, scope is: ${swr.scope}\n`); + + await new Promise(resolve => { + const worker = swr.installing || swr.waiting || swr.active; + if (worker.state === 'activated') { + return resolve(); + } + + worker.addEventListener('statechange', () => { + if (worker.state === 'activated') { + return resolve(); + } + }); + }); +} + +async function unregisterWorker() { + const sw = navigator.serviceWorker; + const swr = await sw.register("service-worker.js", { scope: "" }); + return swr.unregister(); +} + +async function fetchFromWorker() { + const response = await fetch("whatever"); + const text = await response.text(); + console.log(`Response ${text}`); +} +</script>
new file mode 100644 --- /dev/null +++ b/devtools/client/debugger/test/mochitest/examples/service-worker.js @@ -0,0 +1,20 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +dump("Starting\n"); + +self.addEventListener("activate", event => { + dump("Activate\n"); + event.waitUntil(self.clients.claim()); +}); + +self.addEventListener("fetch", event => { + const url = event.request.url; + dump(`Fetch: ${url}\n`); + if (url.includes("whatever")) { + const response = new Response("Service worker response", { statusText: "OK" }); + event.respondWith(response); + } +});
--- a/devtools/client/preferences/debugger.js +++ b/devtools/client/preferences/debugger.js @@ -80,8 +80,9 @@ pref("devtools.debugger.features.autocom pref("devtools.debugger.features.map-expression-bindings", true); pref("devtools.debugger.features.xhr-breakpoints", true); pref("devtools.debugger.features.original-blackbox", true); pref("devtools.debugger.features.event-listeners-breakpoints", true); pref("devtools.debugger.features.dom-mutation-breakpoints", true); pref("devtools.debugger.features.log-points", true); pref("devtools.debugger.features.overlay", true); pref("devtools.debugger.features.inline-preview", true); +pref("devtools.debugger.features.windowless-service-workers", false);
--- a/devtools/client/responsive/browser/tunnel.js +++ b/devtools/client/responsive/browser/tunnel.js @@ -133,17 +133,16 @@ function tunnelToInnerBrowser(outer, inn } if (!inner.isRemoteBrowser) { throw new Error("The inner browser must be remote."); } // Various browser methods access the `frameLoader` property, including: // * `saveBrowser` from contentAreaUtils.js // * `docShellIsActive` from browser.js - // * `hasContentOpener` from browser.js // * `preserveLayers` from browser.js // * `receiveMessage` from SessionStore.jsm // In general, these methods are interested in the `frameLoader` for the content, // so we redirect them to the inner browser's `frameLoader`. outer[FRAME_LOADER] = outer.frameLoader; Object.defineProperty(outer, "frameLoader", { get() { const stack = getStack();
--- a/devtools/client/webconsole/test/browser/browser.ini +++ b/devtools/client/webconsole/test/browser/browser.ini @@ -387,17 +387,16 @@ skip-if = fission [browser_webconsole_input_focus.js] [browser_webconsole_insecure_passwords_about_blank_web_console_warning.js] [browser_webconsole_insecure_passwords_web_console_warning.js] [browser_webconsole_inspect_cross_domain_object.js] skip-if = fission [browser_webconsole_keyboard_accessibility.js] [browser_webconsole_location_debugger_link.js] [browser_webconsole_location_logpoint_debugger_link.js] -skip-if = (os == 'linux' && bits == 64) || (os == 'win') # Bug 1583706 [browser_webconsole_location_styleeditor_link.js] [browser_webconsole_logErrorInPage.js] [browser_webconsole_loglimit.js] [browser_webconsole_logWarningInPage.js] [browser_webconsole_longstring_getter.js] [browser_webconsole_longstring.js] [browser_webconsole_message_categories.js] skip-if = fission
--- a/devtools/server/actors/replay/control.js +++ b/devtools/server/actors/replay/control.js @@ -334,23 +334,25 @@ function closestChild(point) { // The singleton ReplayDebugger, or undefined if it doesn't exist. let gDebugger; //////////////////////////////////////////////////////////////////////////////// // Asynchronous Manifests //////////////////////////////////////////////////////////////////////////////// -// Asynchronous manifest worklists. -const gAsyncManifests = new Set(); -const gAsyncManifestsLowPriority = new Set(); +// Priority levels for asynchronous manifests. +const Priority = { + HIGH: 0, + MEDIUM: 1, + LOW: 2, +}; -function asyncManifestWorklist(lowPriority) { - return lowPriority ? gAsyncManifestsLowPriority : gAsyncManifests; -} +// Asynchronous manifest worklists. +const gAsyncManifests = [new Set(), new Set(), new Set()]; // Send a manifest asynchronously, returning a promise that resolves when the // manifest has been finished. Async manifests have the following properties: // // shouldSkip: Callback invoked before sending the manifest. Returns true if the // manifest should not be sent, and the promise resolved immediately. // // contents: Callback invoked with the executing child when it is being sent. @@ -364,36 +366,36 @@ function asyncManifestWorklist(lowPriori // // snapshot: Optional point at which the associated child should take a snapshot // while heading to the point. // // scanCheckpoint: If the manifest relies on scan data, the saved checkpoint // whose range the child must have scanned. Such manifests do not have side // effects in the child, and can be sent to the active child. // -// lowPriority: True if this manifest should be processed only after all other -// manifests have been processed. +// priority: Optional priority for this manifest. Default is HIGH. // // destination: An optional destination where the child will end up. // // expectedDuration: Optional estimate of the time needed to run the manifest. // // mightRewind: Flag that must be set if the child might restore a snapshot // while processing the manifest. function sendAsyncManifest(manifest) { pokeChildrenSoon(); return new Promise(resolve => { manifest.resolve = resolve; - asyncManifestWorklist(manifest.lowPriority).add(manifest); + const priority = manifest.priority || Priority.HIGH; + gAsyncManifests[priority].add(manifest); }); } // Pick the best async manifest for a child to process. -function pickAsyncManifest(child, lowPriority) { - const worklist = asyncManifestWorklist(lowPriority); +function pickAsyncManifest(child, priority) { + const worklist = gAsyncManifests[priority]; let best = null, bestTime = Infinity; for (const manifest of worklist) { // Prune any manifests that can be skipped. if (manifest.shouldSkip()) { manifest.resolve(); worklist.delete(manifest); @@ -442,22 +444,24 @@ function processAsyncManifest(child) { if (manifest && child == gActiveChild) { // After a child becomes the active child, it gives up on any in progress // async manifest it was processing. sendAsyncManifest(manifest); manifest = null; } if (!manifest) { - manifest = pickAsyncManifest(child, /* lowPriority */ false); + for (const priority of Object.values(Priority)) { + manifest = pickAsyncManifest(child, priority); + if (manifest) { + break; + } + } if (!manifest) { - manifest = pickAsyncManifest(child, /* lowPriority */ true); - if (!manifest) { - return false; - } + return false; } } child.asyncManifest = manifest; if ( manifest.point && maybeReachPoint(child, manifest.point, manifest.snapshot) @@ -1034,17 +1038,17 @@ async function queuePauseData({ if (!data.restoredSnapshot) { addPauseData(point, data, trackCached); child.divergedFromRecording = true; } }, point, snapshot, expectedDuration: 250, - lowPriority: true, + priority: Priority.LOW, mightRewind: true, }); } function addPauseData(point, data, trackCached) { if (data.paintData) { // Atomize paint data strings to ensure that we don't store redundant // strings for execution points with the same paint data. @@ -1571,17 +1575,17 @@ async function evaluateLogpoint({ if (!fast) { child.divergedFromRecording = true; } } }, point, snapshot, expectedDuration: 250, - lowPriority: true, + priority: Priority.MEDIUM, mightRewind: true, }); } // Asynchronously invoke a logpoint's callback with all results from hitting // the logpoint in the range of the recording covered by checkpoint. async function findLogpointHits( checkpoint,
--- a/dom/animation/test/chrome/test_running_on_compositor.html +++ b/dom/animation/test/chrome/test_running_on_compositor.html @@ -1112,64 +1112,107 @@ promise_test(async t => { properties.forEach(property => { assert_true(property.runningOnCompositor, property.property + ' is running on the compositor'); }); }, 'Multiple transform-like properties animation runs on the compositor'); promise_test(async t => { const div = addDiv(t); + const animation = div.animate({ offsetPath: ['none', 'none'] }, + 100 * MS_PER_SEC); + + await waitForAnimationReadyToRestyle(animation); + await waitForPaints(); + + assert_animation_is_running_on_compositor(animation, + 'offset-path animation should be running on the compositor even if ' + + 'it is always none'); +}, 'offset-path none animation runs on the compositor'); + +promise_test(async t => { + const div = addDiv(t); const animation = div.animate({ offsetPath: ['path("M0 0l100 100")', 'path("M0 0l200 200")'] }, 100 * MS_PER_SEC); await waitForAnimationReadyToRestyle(animation); await waitForPaints(); assert_animation_is_running_on_compositor(animation, 'offset-path animation should be running on the compositor'); }, 'offset-path animation runs on the compositor'); -// FIXME: Bug 1592787: We should stop sending offset-* properties to the -// compositor and skip restyling entirely if offset-path is none and we don't -// have any animation of it. promise_test(async t => { const div = addDiv(t); const animation = div.animate({ offsetDistance: ['0%', '100%'] }, 100 * MS_PER_SEC); await waitForAnimationReadyToRestyle(animation); await waitForPaints(); + assert_animation_is_not_running_on_compositor(animation, + 'offset-distance animation is not running on the compositor because ' + + 'offset-path is none'); + + const newAnim = div.animate({ offsetPath: ['None', 'None'] }, + 100 * MS_PER_SEC); + await waitForAnimationReadyToRestyle(newAnim); + await waitForPaints(); + assert_animation_is_running_on_compositor(animation, 'offset-distance animation should be running on the compositor'); + assert_animation_is_running_on_compositor(newAnim, + 'new added offset-path animation should be running on the compositor'); }, 'offset-distance animation runs on the compositor'); promise_test(async t => { const div = addDiv(t); const animation = div.animate({ offsetRotate: ['0deg', '45deg'] }, 100 * MS_PER_SEC); await waitForAnimationReadyToRestyle(animation); await waitForPaints(); + assert_animation_is_not_running_on_compositor(animation, + 'offset-rotate animation is not running on the compositor because ' + + 'offset-path is none'); + + const newAnim = div.animate({ offsetPath: ['None', 'None'] }, + 100 * MS_PER_SEC); + await waitForAnimationReadyToRestyle(newAnim); + await waitForPaints(); + assert_animation_is_running_on_compositor(animation, 'offset-rotate animation should be running on the compositor'); + assert_animation_is_running_on_compositor(newAnim, + 'new added offset-path animation should be running on the compositor'); }, 'offset-rotate animation runs on the compositor'); promise_test(async t => { const div = addDiv(t); const animation = div.animate({ offsetAnchor: ['0% 0%', '100% 100%'] }, 100 * MS_PER_SEC); await waitForAnimationReadyToRestyle(animation); await waitForPaints(); + assert_animation_is_not_running_on_compositor(animation, + 'offset-anchor animation is not running on the compositor because ' + + 'offset-path is none'); + + const newAnim = div.animate({ offsetPath: ['None', 'None'] }, + 100 * MS_PER_SEC); + await waitForAnimationReadyToRestyle(newAnim); + await waitForPaints(); + assert_animation_is_running_on_compositor(animation, 'offset-anchor animation should be running on the compositor'); + assert_animation_is_running_on_compositor(newAnim, + 'new added offset-path animation should be running on the compositor'); }, 'offset-anchor animation runs on the compositor'); promise_test(async t => { const div = addDiv(t); const animation = div.animate({ translate: ['0px', '100px'], rotate: ['0deg', '45deg'], transform: ['translate(0px)', 'translate(100px)'],
--- a/dom/base/BindContext.h +++ b/dom/base/BindContext.h @@ -4,19 +4,16 @@ * 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/. */ /* State that is passed down to BindToTree. */ #ifndef mozilla_dom_BindContext_h__ #define mozilla_dom_BindContext_h__ -#ifdef MOZ_XBL -# include "nsXBLBinding.h" -#endif #include "mozilla/Attributes.h" #include "mozilla/AutoRestore.h" #include "mozilla/dom/Document.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/ShadowRoot.h" namespace mozilla { namespace dom { @@ -94,29 +91,16 @@ struct MOZ_STACK_CLASS BindContext final mInUncomposedDoc(aParentElement.IsInUncomposedDoc()), mSubtreeRootChanges(true), mCollectingDisplayedNodeDataDuringLoad( ShouldCollectDisplayedNodeDataDuringLoad(mInComposedDoc, mDoc, aParentElement)) { MOZ_ASSERT(mInComposedDoc, "Binding NAC in a disconnected subtree?"); } -#ifdef MOZ_XBL - // This is meant to be used to bind XBL anonymous content. - BindContext(nsXBLBinding& aBinding, Element& aParentElement) - : mDoc(*aParentElement.OwnerDoc()), - mBindingParent(aBinding.GetBoundElement()), - mInComposedDoc(aParentElement.IsInComposedDoc()), - mInUncomposedDoc(aParentElement.IsInUncomposedDoc()), - mSubtreeRootChanges(true), - mCollectingDisplayedNodeDataDuringLoad( - ShouldCollectDisplayedNodeDataDuringLoad(mInComposedDoc, mDoc, - aParentElement)) {} -#endif - bool CollectingDisplayedNodeDataDuringLoad() const { return mCollectingDisplayedNodeDataDuringLoad; } private: static bool IsLikelyUndisplayed(const nsINode& aParent) { return aParent.IsAnyOfHTMLElements(nsGkAtoms::style, nsGkAtoms::script); }
--- a/dom/base/CharacterData.cpp +++ b/dom/base/CharacterData.cpp @@ -24,19 +24,16 @@ #include "nsReadableUtils.h" #include "mozilla/InternalMutationEvent.h" #include "nsIURI.h" #include "nsCOMPtr.h" #include "nsDOMString.h" #include "nsChangeHint.h" #include "nsCOMArray.h" #include "mozilla/dom/DirectionalityUtils.h" -#ifdef MOZ_XBL -# include "nsBindingManager.h" -#endif #include "nsCCUncollectableMarker.h" #include "mozAutoDocUpdate.h" #include "nsTextNode.h" #include "nsBidiUtils.h" #include "PLDHashTable.h" #include "mozilla/Sprintf.h" #include "nsWindowSizes.h" #include "nsWrapperCacheInlines.h" @@ -510,20 +507,16 @@ nsresult CharacterData::BindToTree(BindC } void CharacterData::UnbindFromTree(bool aNullParent) { // Unset frame flags; if we need them again later, they'll get set again. UnsetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE | NS_REFRAME_IF_WHITESPACE); HandleShadowDOMRelatedRemovalSteps(aNullParent); -#ifdef MOZ_XBL - Document* document = GetComposedDoc(); -#endif - if (aNullParent) { if (IsRootOfNativeAnonymousSubtree()) { MutationObservers::NotifyNativeAnonymousChildListChange(this, true); } if (GetParent()) { NS_RELEASE(mParent); } else { mParent = nullptr; @@ -535,29 +528,16 @@ void CharacterData::UnbindFromTree(bool if (aNullParent || !mParent->IsInShadowTree()) { UnsetFlags(NODE_IS_IN_SHADOW_TREE); // Begin keeping track of our subtree root. SetSubtreeRootPointer(aNullParent ? this : mParent->SubtreeRoot()); } -#ifdef MOZ_XBL - if (document && !GetContainingShadow()) { - // Notify XBL- & nsIAnonymousContentCreator-generated - // anonymous content that the document is changing. - // Unlike XBL, bindings for web components shadow DOM - // do not get uninstalled. - if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) { - nsContentUtils::AddScriptRunner(new RemoveFromBindingManagerRunnable( - document->BindingManager(), this, document)); - } - } -#endif - nsExtendedContentSlots* slots = GetExistingExtendedContentSlots(); if (slots) { slots->mBindingParent = nullptr; if (aNullParent || !mParent->IsInShadowTree()) { slots->mContainingShadow = nullptr; } }
--- a/dom/base/CharacterData.h +++ b/dom/base/CharacterData.h @@ -164,20 +164,16 @@ class CharacterData : public nsIContent void SaveSubtreeState() final {} #ifdef DEBUG void List(FILE* out, int32_t aIndent) const override {} void DumpContent(FILE* out, int32_t aIndent, bool aDumpAll) const override {} #endif -#ifdef MOZ_XBL - nsXBLBinding* DoGetXBLBinding() const final { return nullptr; } -#endif - bool IsNodeOfType(uint32_t aFlags) const override { return false; } bool IsLink(nsIURI** aURI) const final { *aURI = nullptr; return false; } nsresult Clone(dom::NodeInfo* aNodeInfo, nsINode** aResult) const override {
--- a/dom/base/ChildIterator.cpp +++ b/dom/base/ChildIterator.cpp @@ -3,19 +3,16 @@ /* 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/. */ #include "ChildIterator.h" #include "nsContentUtils.h" #include "mozilla/dom/Document.h" #include "mozilla/dom/HTMLSlotElement.h" -#ifdef MOZ_XBL -# include "mozilla/dom/XBLChildrenElement.h" -#endif #include "mozilla/dom/ShadowRoot.h" #include "nsIAnonymousContentCreator.h" #include "nsIFrame.h" #include "nsCSSAnonBoxes.h" namespace mozilla { namespace dom { @@ -43,27 +40,17 @@ nsIContent* ExplicitChildIterator::GetNe ? assignedNodes[mIndexInInserted++]->AsContent() : nullptr; if (!mChild) { mIndexInInserted = 0; } return mChild; } -#ifdef MOZ_XBL - MOZ_ASSERT(mChild->IsActiveChildrenElement()); - auto* childrenElement = static_cast<XBLChildrenElement*>(mChild); - if (mIndexInInserted < childrenElement->InsertedChildrenLength()) { - return childrenElement->InsertedChild(mIndexInInserted++); - } - mIndexInInserted = 0; - mChild = mChild->GetNextSibling(); -#else MOZ_ASSERT_UNREACHABLE("This needs to be revisited"); -#endif } else if (mDefaultChild) { // If we're already in default content, check if there are more nodes there MOZ_ASSERT(mChild); MOZ_ASSERT(mChild->IsActiveChildrenElement()); mDefaultChild = mDefaultChild->GetNextSibling(); if (mDefaultChild) { return mDefaultChild; @@ -89,40 +76,17 @@ nsIContent* ExplicitChildIterator::GetNe } else if (mChild) { // in the middle of the child list mChild = mChild->GetNextSibling(); } // Iterate until we find a non-insertion point, or an insertion point with // content. while (mChild) { if (mChild->IsActiveChildrenElement()) { -#ifdef MOZ_XBL - // If the current child being iterated is a content insertion point - // then the iterator needs to return the nodes distributed into - // the content insertion point. - auto* childrenElement = static_cast<XBLChildrenElement*>(mChild); - if (childrenElement->HasInsertedChildren()) { - // Iterate through elements projected on insertion point. - mIndexInInserted = 1; - return childrenElement->InsertedChild(0); - } - - // Insertion points inside fallback/default content - // are considered inactive and do not get assigned nodes. - mDefaultChild = mChild->GetFirstChild(); - if (mDefaultChild) { - return mDefaultChild; - } - - // If we have an insertion point with no assigned nodes and - // no default content, move on to the next node. - mChild = mChild->GetNextSibling(); -#else MOZ_ASSERT_UNREACHABLE("This needs to be revisited"); -#endif } else { // mChild is not an insertion point, thus it is the next node to // return from this iterator. break; } } return mChild; @@ -138,27 +102,16 @@ void FlattenedChildIterator::Init(bool a // FlattenedChildIterators with Element. if (mParent->IsElement()) { if (ShadowRoot* shadow = mParent->AsElement()->GetShadowRoot()) { mParent = shadow; mXBLInvolved = Some(true); return; } } - -#ifdef MOZ_XBL - nsXBLBinding* binding = - mParent->OwnerDoc()->BindingManager()->GetBindingWithContent(mParent); - - if (binding) { - MOZ_ASSERT(binding->GetAnonymousContent()); - mParent = binding->GetAnonymousContent(); - mXBLInvolved = Some(true); - } -#endif } bool FlattenedChildIterator::ComputeWhetherXBLIsInvolved() const { MOZ_ASSERT(mXBLInvolved.isNothing()); // We set mXBLInvolved to true if either the node we're iterating has a // binding with content attached to it (in which case it is handled in Init), // the node is generated XBL content and has an <xbl:children> child, or the // node is a <slot> element. @@ -206,23 +159,17 @@ nsIContent* ExplicitChildIterator::Get() // When mParentAsSlot is set, mChild is always set to the current child. It // does not matter whether mChild is an assigned node or a fallback content. if (mParentAsSlot) { return mChild; } if (mIndexInInserted) { -#ifdef MOZ_XBL - MOZ_ASSERT(mChild->IsActiveChildrenElement()); - auto* childrenElement = static_cast<XBLChildrenElement*>(mChild); - return childrenElement->InsertedChild(mIndexInInserted - 1); -#else MOZ_ASSERT_UNREACHABLE("This needs to be revisited"); -#endif } return mDefaultChild ? mDefaultChild : mChild; } nsIContent* ExplicitChildIterator::GetPreviousChild() { // If we're already in the inserted-children array, look there first if (mIndexInInserted) { @@ -235,28 +182,17 @@ nsIContent* ExplicitChildIterator::GetPr : nullptr; if (!mChild) { mIsFirst = true; } return mChild; } -#ifdef MOZ_XBL - // NB: mIndexInInserted points one past the last returned child so we need - // to look *two* indices back in order to return the previous child. - MOZ_ASSERT(mChild->IsActiveChildrenElement()); - auto* childrenElement = static_cast<XBLChildrenElement*>(mChild); - if (--mIndexInInserted) { - return childrenElement->InsertedChild(mIndexInInserted - 1); - } - mChild = mChild->GetPreviousSibling(); -#else MOZ_ASSERT_UNREACHABLE("This needs to be revisited"); -#endif } else if (mDefaultChild) { // If we're already in default content, check if there are more nodes there mDefaultChild = mDefaultChild->GetPreviousSibling(); if (mDefaultChild) { return mDefaultChild; } mChild = mChild->GetPreviousSibling(); @@ -279,35 +215,17 @@ nsIContent* ExplicitChildIterator::GetPr mChild = mParent->GetLastChild(); } // Iterate until we find a non-insertion point, or an insertion point with // content. while (mChild) { if (mChild->IsActiveChildrenElement()) { -#ifdef MOZ_XBL - // If the current child being iterated is a content insertion point - // then the iterator needs to return the nodes distributed into - // the content insertion point. - auto* childrenElement = static_cast<XBLChildrenElement*>(mChild); - if (childrenElement->HasInsertedChildren()) { - mIndexInInserted = childrenElement->InsertedChildrenLength(); - return childrenElement->InsertedChild(mIndexInInserted - 1); - } - - mDefaultChild = mChild->GetLastChild(); - if (mDefaultChild) { - return mDefaultChild; - } - - mChild = mChild->GetPreviousSibling(); -#else MOZ_ASSERT_UNREACHABLE("This needs to be revisited"); -#endif } else { // mChild is not an insertion point, thus it is the next node to // return from this iterator. break; } } if (!mChild) {
--- a/dom/base/Document.cpp +++ b/dom/base/Document.cpp @@ -174,19 +174,16 @@ #include "nsICookiePermission.h" #include "nsICookieService.h" #include "nsBidiUtils.h" #include "nsContentCreatorFunctions.h" #include "nsIScriptContext.h" -#ifdef MOZ_XBL -# include "nsBindingManager.h" -#endif #include "nsHTMLDocument.h" #include "nsIRequest.h" #include "mozilla/dom/BlobURLProtocolHandler.h" #include "nsCharsetSource.h" #include "nsIParser.h" #include "nsIContentSink.h" @@ -1943,25 +1940,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_ } else { NS_IMPL_CYCLE_COLLECTION_DESCRIBE(Document, tmp->mRefCnt.get()) } if (!nsINode::Traverse(tmp, cb)) { return NS_SUCCESS_INTERRUPTED_TRAVERSE; } -#ifdef MOZ_XBL - if (tmp->mMaybeEndOutermostXBLUpdateRunner) { - // The cached runnable keeps a reference to the document object.. - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME( - cb, "mMaybeEndOutermostXBLUpdateRunner.mObj"); - cb.NoteXPCOMChild(ToSupports(tmp)); - } -#endif - tmp->mExternalResourceMap.Traverse(&cb); // Traverse all Document pointer members. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSecurityInfo) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDisplayDocument) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFontFaceSet) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReadyForIdle) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentL10n) @@ -2080,19 +2068,16 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Do tmp->DisconnectChild(child); child->UnbindFromTree(); } tmp->UnlinkOriginalDocumentIfStatic(); tmp->mCachedRootElement = nullptr; // Avoid a dangling pointer NS_IMPL_CYCLE_COLLECTION_UNLINK(mDisplayDocument) -#ifdef MOZ_XBL - NS_IMPL_CYCLE_COLLECTION_UNLINK(mMaybeEndOutermostXBLUpdateRunner) -#endif NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMImplementation) NS_IMPL_CYCLE_COLLECTION_UNLINK(mImageMaps) NS_IMPL_CYCLE_COLLECTION_UNLINK(mCachedEncoder) NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentTimeline) NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingAnimationTracker) NS_IMPL_CYCLE_COLLECTION_UNLINK(mTemplateContentsOwner) NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildrenCollection) NS_IMPL_CYCLE_COLLECTION_UNLINK(mImages); @@ -5908,32 +5893,16 @@ void Document::TryChannelCharset(nsIChan static inline void AssertNoStaleServoDataIn(nsINode& aSubtreeRoot) { #ifdef DEBUG for (nsINode* node : ShadowIncludingTreeIterator(aSubtreeRoot)) { const Element* element = Element::FromNode(node); if (!element) { continue; } MOZ_ASSERT(!element->HasServoData()); -# ifdef MOZ_XBL - if (nsXBLBinding* binding = element->GetXBLBinding()) { - if (nsXBLBinding* bindingWithContent = binding->GetBindingWithContent()) { - nsIContent* content = bindingWithContent->GetAnonymousContent(); - // Need to do this instead of just AssertNoStaleServoDataIn(*content), - // because the parent of the children of the <content> element isn't the - // <content> element, but the bound element, and that confuses - // GetNextNode a lot. - MOZ_ASSERT(!content->AsElement()->HasServoData()); - for (nsINode* child = content->GetFirstChild(); child; - child = child->GetNextSibling()) { - AssertNoStaleServoDataIn(*child); - } - } - } -# endif } #endif } already_AddRefed<PresShell> Document::CreatePresShell( nsPresContext* aContext, nsViewManager* aViewManager) { MOZ_ASSERT(!mPresShell, "We have a presshell already!"); @@ -6919,76 +6888,43 @@ bool Document::RemoveObserver(nsIDocumen if (!mInDestructor) { RemoveMutationObserver(aObserver); return mObservers.RemoveElement(aObserver); } return mObservers.Contains(aObserver); } -#ifdef MOZ_XBL -void Document::MaybeEndOutermostXBLUpdate() { - // Only call BindingManager()->EndOutermostUpdate() when - // we're not in an update and it is safe to run scripts. - if (mUpdateNestLevel == 0 && mInXBLUpdate) { - if (nsContentUtils::IsSafeToRunScript()) { - mInXBLUpdate = false; - BindingManager()->EndOutermostUpdate(); - } else if (!mInDestructor) { - if (!mMaybeEndOutermostXBLUpdateRunner) { - mMaybeEndOutermostXBLUpdateRunner = - NewRunnableMethod("Document::MaybeEndOutermostXBLUpdate", this, - &Document::MaybeEndOutermostXBLUpdate); - } - nsContentUtils::AddScriptRunner(mMaybeEndOutermostXBLUpdateRunner); - } - } -} -#endif - void Document::BeginUpdate() { // If the document is going away, then it's probably okay to do things to it // in the wrong DocGroup. We're unlikely to run JS or do anything else // observable at this point. We reach this point when cycle collecting a // <link> element and the unlink code removes a style sheet. // // TODO(emilio): Style updates are gone, can this happen now? if (mDocGroup && !mIsGoingAway && !mInUnlinkOrDeletion && !mIgnoreDocGroupMismatches) { mDocGroup->ValidateAccess(); } -#ifdef MOZ_XBL - if (mUpdateNestLevel == 0 && !mInXBLUpdate) { - mInXBLUpdate = true; - BindingManager()->BeginOutermostUpdate(); - } -#endif - ++mUpdateNestLevel; nsContentUtils::AddScriptBlocker(); NS_DOCUMENT_NOTIFY_OBSERVERS(BeginUpdate, (this)); } void Document::EndUpdate() { const bool reset = !mPendingMaybeEditingStateChanged; mPendingMaybeEditingStateChanged = true; NS_DOCUMENT_NOTIFY_OBSERVERS(EndUpdate, (this)); nsContentUtils::RemoveScriptBlocker(); --mUpdateNestLevel; -#ifdef MOZ_XBL - // This set of updates may have created XBL bindings. Let the - // binding manager know we're done. - MaybeEndOutermostXBLUpdate(); -#endif - MaybeInitializeFinalizeFrameLoaders(); if (mXULBroadcastManager) { mXULBroadcastManager->MaybeBroadcast(); } if (reset) { mPendingMaybeEditingStateChanged = false; } @@ -7869,88 +7805,29 @@ already_AddRefed<nsINode> Document::Impo Element* Document::GetBindingParent(nsINode& aNode) { nsCOMPtr<nsIContent> content(do_QueryInterface(&aNode)); if (!content) return nullptr; nsIContent* bindingParent = content->GetBindingParent(); return bindingParent ? bindingParent->AsElement() : nullptr; } -#ifdef MOZ_XBL -static Element* GetElementByAttribute(Element* aElement, nsAtom* aAttrName, - const nsAString& aAttrValue, - bool aUniversalMatch) { - if (aUniversalMatch ? aElement->HasAttr(kNameSpaceID_None, aAttrName) - : aElement->AttrValueIs(kNameSpaceID_None, aAttrName, - aAttrValue, eCaseMatters)) { - return aElement; - } - - for (nsIContent* child = aElement->GetFirstChild(); child; - child = child->GetNextSibling()) { - if (!child->IsElement()) { - continue; - } - - Element* matchedElement = GetElementByAttribute( - child->AsElement(), aAttrName, aAttrValue, aUniversalMatch); - if (matchedElement) return matchedElement; - } - - return nullptr; -} -#endif - Element* Document::GetAnonymousElementByAttribute( nsIContent* aElement, nsAtom* aAttrName, const nsAString& aAttrValue) const { -#ifdef MOZ_XBL - nsINodeList* nodeList = BindingManager()->GetAnonymousNodesFor(aElement); - if (!nodeList) return nullptr; - - uint32_t length = nodeList->Length(); - - bool universalMatch = aAttrValue.EqualsLiteral("*"); - - for (uint32_t i = 0; i < length; ++i) { - Element* current = Element::FromNode(nodeList->Item(i)); - if (!current) { - continue; - } - - Element* matchedElm = - GetElementByAttribute(current, aAttrName, aAttrValue, universalMatch); - if (matchedElm) return matchedElm; - } - return nullptr; -#else - return nullptr; -#endif } Element* Document::GetAnonymousElementByAttribute(Element& aElement, const nsAString& aAttrName, const nsAString& aAttrValue) { -#ifdef MOZ_XBL - RefPtr<nsAtom> attribute = NS_Atomize(aAttrName); - - return GetAnonymousElementByAttribute(&aElement, attribute, aAttrValue); -#else return nullptr; -#endif -} - -nsINodeList* Document::GetAnonymousNodes(Element& aElement) { -#ifdef MOZ_XBL - return BindingManager()->GetAnonymousNodesFor(&aElement); -#else - return nullptr; -#endif -} +} + +nsINodeList* Document::GetAnonymousNodes(Element& aElement) { return nullptr; } already_AddRefed<nsRange> Document::CreateRange(ErrorResult& rv) { RefPtr<nsRange> range = new nsRange(this); nsresult res = range->CollapseTo(this, 0); if (NS_FAILED(res)) { rv.Throw(res); return nullptr; } @@ -9297,26 +9174,16 @@ nsINode* Document::AdoptNode(nsINode& aA } while ((doc = doc->GetInProcessParentDocument())); // Remove from parent. nsCOMPtr<nsINode> parent = adoptedNode->GetParentNode(); if (parent) { parent->RemoveChildNode(adoptedNode->AsContent(), true); } else { MOZ_ASSERT(!adoptedNode->IsInUncomposedDoc()); - -#ifdef MOZ_XBL - // If we're adopting a node that's not in a document, it might still - // have a binding applied. Remove the binding from the element now - // that it's getting adopted into a new document. - // TODO Fully tear down the binding. - if (Element* element = Element::FromNode(adoptedNode)) { - element->SetXBLBinding(nullptr); - } -#endif } break; } case DOCUMENT_NODE: { rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); return nullptr; } @@ -14193,25 +14060,16 @@ void Document::AddSizeOfNodeTree(nsINode for (nsIContent* anonKid : anonKids) { AddSizeOfNodeTree(*anonKid, aWindowSizes); } if (auto* element = Element::FromNode(aNode)) { if (ShadowRoot* shadow = element->GetShadowRoot()) { AddSizeOfNodeTree(*shadow, aWindowSizes); } - -#ifdef MOZ_XBL - for (nsXBLBinding* binding = element->GetXBLBinding(); binding; - binding = binding->GetBaseBinding()) { - if (nsIContent* anonContent = binding->GetAnonymousContent()) { - AddSizeOfNodeTree(*anonContent, aWindowSizes); - } - } -#endif } } // NOTE(emilio): If you feel smart and want to change this function to use // GetNextNode(), think twice, since you'd need to handle <xbl:content> in a // sane way, and kids of <content> won't point to the parent, so we'd never // find the root node where we should stop at. for (nsIContent* kid = aNode.GetFirstChild(); kid;
--- a/dom/base/Document.h +++ b/dom/base/Document.h @@ -80,19 +80,16 @@ namespace mozilla { namespace dom { class ElementCreationOptionsOrString; } // namespace dom } // namespace mozilla #endif // MOZILLA_INTERNAL_API class gfxUserFontSet; class imgIRequest; -#ifdef MOZ_XBL -class nsBindingManager; -#endif class nsCachableElementsByNameNodeList; class nsCommandManager; class nsContentList; class nsIDocShell; class nsDocShell; class nsDOMNavigationTiming; class nsFrameLoader; class nsGlobalWindowInner; @@ -1808,20 +1805,16 @@ class Document : public nsINode, nsresult InitFeaturePolicy(nsIChannel* aChannel); nsresult InitReferrerInfo(nsIChannel* aChannel); void PostUnblockOnloadEvent(); void DoUnblockOnload(); -#ifdef MOZ_XBL - void MaybeEndOutermostXBLUpdate(); -#endif - void RetrieveRelevantHeaders(nsIChannel* aChannel); void TryChannelCharset(nsIChannel* aChannel, int32_t& aCharsetSource, NotNull<const Encoding*>& aEncoding, nsHtml5TreeOpExecutor* aExecutor); void DispatchContentLoadedEvents(); @@ -2389,22 +2382,16 @@ class Document : public nsINode, // Triggers an update of <svg:use> element shadow trees. void UpdateSVGUseElementShadowTrees() { if (mSVGUseElementsNeedingShadowTreeUpdate.IsEmpty()) { return; } DoUpdateSVGUseElementShadowTrees(); } -#ifdef MOZ_XBL - nsBindingManager* BindingManager() const { - return mNodeInfoManager->GetBindingManager(); - } -#endif - /** * Only to be used inside Gecko, you can't really do anything with the * pointer outside Gecko anyway. */ nsNodeInfoManager* NodeInfoManager() const { return mNodeInfoManager; } /** * Reset the document using the given channel and loadgroup. This works @@ -5289,19 +5276,16 @@ class Document : public nsINode, CSSCoord mMinWidth; CSSCoord mMaxWidth; CSSCoord mMinHeight; CSSCoord mMaxHeight; RefPtr<EventListenerManager> mListenerManager; -#ifdef MOZ_XBL - nsCOMPtr<nsIRunnable> mMaybeEndOutermostXBLUpdateRunner; -#endif nsCOMPtr<nsIRequest> mOnloadBlocker; nsTArray<RefPtr<StyleSheet>> mAdditionalSheets[AdditionalSheetTypeCount]; // Member to store out last-selected stylesheet set. nsString mLastStyleSheetSet; nsString mPreferredStyleSheetSet;
--- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -11,16 +11,17 @@ */ #include "mozilla/dom/ElementInlines.h" #include "AnimationCommon.h" #include "mozilla/DebugOnly.h" #include "mozilla/StaticPrefs_dom.h" #include "mozilla/StaticPrefs_layout.h" +#include "mozilla/StaticPrefs_full_screen_api.h" #include "mozilla/dom/Animation.h" #include "mozilla/dom/Attr.h" #include "mozilla/dom/BindContext.h" #include "mozilla/dom/Flex.h" #include "mozilla/dom/Grid.h" #include "mozilla/dom/Link.h" #include "mozilla/dom/MutationObservers.h" #include "mozilla/dom/ScriptLoader.h" @@ -89,22 +90,16 @@ # include "nsXULElement.h" #endif /* MOZ_XUL */ #include "SVGElement.h" #include "nsFrameSelection.h" #ifdef DEBUG # include "nsRange.h" #endif -#ifdef MOZ_XBL -# include "nsXBLPrototypeBinding.h" -# include "nsBindingManager.h" -# include "nsXBLBinding.h" -# include "nsXBLService.h" -#endif #include "nsPIDOMWindow.h" #include "mozilla/dom/DOMRect.h" #include "nsSVGUtils.h" #include "nsLayoutUtils.h" #include "nsGkAtoms.h" #include "ChildIterator.h" #include "nsIDOMEventListener.h" @@ -262,23 +257,17 @@ Element::QueryInterface(REFNSIID aIID, v } NS_ASSERTION(aInstancePtr, "QueryInterface requires a non-NULL destination!"); nsresult rv = FragmentOrElement::QueryInterface(aIID, aInstancePtr); if (NS_SUCCEEDED(rv)) { return NS_OK; } -#if MOZ_XBL - // Give the binding manager a chance to get an interface for this element. - return OwnerDoc()->BindingManager()->GetBindingImplementation(this, aIID, - aInstancePtr); -#else return NS_NOINTERFACE; -#endif } EventStates Element::IntrinsicState() const { return IsEditable() ? NS_EVENT_STATE_MOZ_READWRITE : NS_EVENT_STATE_MOZ_READONLY; } void Element::NotifyStateChange(EventStates aStates) { @@ -377,58 +366,16 @@ void Element::Focus(const FocusOptions& void Element::SetTabIndex(int32_t aTabIndex, mozilla::ErrorResult& aError) { nsAutoString value; value.AppendInt(aTabIndex); SetAttr(nsGkAtoms::tabindex, value, aError); } -#ifdef MOZ_XBL -void Element::SetXBLBinding(nsXBLBinding* aBinding, - nsBindingManager* aOldBindingManager) { - nsBindingManager* bindingManager; - if (aOldBindingManager) { - MOZ_ASSERT(!aBinding, - "aOldBindingManager should only be provided " - "when removing a binding."); - bindingManager = aOldBindingManager; - } else { - bindingManager = OwnerDoc()->BindingManager(); - } - - // After this point, aBinding will be the most-derived binding for aContent. - // If we already have a binding for aContent, make sure to - // remove it from the attached stack. Otherwise we might end up firing its - // constructor twice (if aBinding inherits from it) or firing its constructor - // after aContent has been deleted (if aBinding is null and the content node - // dies before we process mAttachedStack). - RefPtr<nsXBLBinding> oldBinding = GetXBLBinding(); - if (oldBinding) { - bindingManager->RemoveFromAttachedQueue(oldBinding); - } - - if (aBinding) { - SetFlags(NODE_MAY_BE_IN_BINDING_MNGR); - nsExtendedDOMSlots* slots = ExtendedDOMSlots(); - slots->mXBLBinding = aBinding; - bindingManager->AddBoundContent(this); - } else { - nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots(); - if (slots) { - slots->mXBLBinding = nullptr; - } - bindingManager->RemoveBoundContent(this); - if (oldBinding) { - oldBinding->SetBoundElement(nullptr); - } - } -} -#endif - void Element::SetShadowRoot(ShadowRoot* aShadowRoot) { nsExtendedDOMSlots* slots = ExtendedDOMSlots(); slots->mShadowRoot = aShadowRoot; } void Element::Blur(mozilla::ErrorResult& aError) { if (!ShouldBlur(this)) { return; @@ -1060,21 +1007,17 @@ already_AddRefed<ShadowRoot> Element::At aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); return nullptr; } /** * 3. If context object is a shadow host, then throw * an "InvalidStateError" DOMException. */ - if (GetShadowRoot() -#ifdef MOZ_XBL - || GetXBLBinding() -#endif - ) { + if (GetShadowRoot()) { aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr; } if (StaticPrefs::dom_webcomponents_shadowdom_report_usage()) { OwnerDoc()->ReportShadowDOMUsage(); } @@ -1591,29 +1534,16 @@ nsresult Element::BindToTree(BindContext // because it has to happen after updating the parent pointer, but before // recursively binding the kids. if (IsHTMLElement()) { SetDirOnBind(this, nsIContent::FromNode(aParent)); } UpdateEditableState(false); -#ifdef MOZ_XBL - // If we had a pre-existing XBL binding, we might have anonymous children that - // also need to be told that they are moving. - if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) { - nsXBLBinding* binding = - aContext.OwnerDoc().BindingManager()->GetBindingWithContent(this); - - if (binding) { - binding->BindAnonymousContent(binding->GetAnonymousContent(), this); - } - } -#endif - // Call BindToTree on shadow root children. nsresult rv; if (ShadowRoot* shadowRoot = GetShadowRoot()) { rv = shadowRoot->Bind(); NS_ENSURE_SUCCESS(rv, rv); } // Now recurse into our kids. Ensure this happens after binding the shadow @@ -1684,44 +1614,16 @@ nsresult Element::BindToTree(BindContext "Bound to wrong binding parent"); MOZ_ASSERT(aParent.IsInUncomposedDoc() == IsInUncomposedDoc()); MOZ_ASSERT(aParent.IsInComposedDoc() == IsInComposedDoc()); MOZ_ASSERT(aParent.IsInShadowTree() == IsInShadowTree()); MOZ_ASSERT(aParent.SubtreeRoot() == SubtreeRoot()); return NS_OK; } -#ifdef MOZ_XBL -RemoveFromBindingManagerRunnable::RemoveFromBindingManagerRunnable( - nsBindingManager* aManager, nsIContent* aContent, Document* aDoc) - : mozilla::Runnable("dom::RemoveFromBindingManagerRunnable"), - mManager(aManager), - mContent(aContent), - mDoc(aDoc) {} - -RemoveFromBindingManagerRunnable::~RemoveFromBindingManagerRunnable() {} - -NS_IMETHODIMP -RemoveFromBindingManagerRunnable::Run() { - // It may be the case that the element was removed from the - // DOM, causing this runnable to be created, then inserted back - // into the document before the this runnable had a chance to - // tear down the binding. Only tear down the binding if the element - // is still no longer in the DOM. nsXBLService::LoadBinding tears - // down the old binding if the element is inserted back into the - // DOM and loads a different binding. - if (!mContent->IsInComposedDoc()) { - mManager->RemovedFromDocumentInternal(mContent, mDoc, - nsBindingManager::eRunDtor); - } - - return NS_OK; -} -#endif - bool WillDetachFromShadowOnUnbind(const Element& aElement, bool aNullParent) { // If our parent still is in a shadow tree by now, and we're not removing // ourselves from it, then we're still going to be in a shadow tree after // this. return aElement.IsInShadowTree() && (aNullParent || !aElement.GetParent()->IsInShadowTree()); } @@ -1859,32 +1761,16 @@ void Element::UnbindFromTree(bool aNullP slots->mBindingParent = nullptr; } if (aNullParent || !mParent->IsInShadowTree()) { slots->mContainingShadow = nullptr; } } if (document) { -#ifdef MOZ_XBL - if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) { - // Notify XBL- & nsIAnonymousContentCreator-generated anonymous content - // that the document is changing. - nsContentUtils::AddScriptRunner(new RemoveFromBindingManagerRunnable( - document->BindingManager(), this, document)); - nsXBLBinding* binding = - document->BindingManager()->GetBindingWithContent(this); - if (binding) { - nsXBLBinding::UnbindAnonymousContent(document, - binding->GetAnonymousContent(), - /* aNullParent */ false); - } - } -#endif - // Disconnected must be enqueued whenever a connected custom element becomes // disconnected. CustomElementData* data = GetCustomElementData(); if (data) { if (data->mState == CustomElementData::State::eCustom) { nsContentUtils::EnqueueLifecycleCallback(Document::eDisconnected, this); } else { // Remove an unresolved custom element that is a candidate for upgrade @@ -2403,25 +2289,16 @@ nsresult Element::SetAttrAndNotify( oldValue = nullptr; } } else { // No need to conditionally assign null here. If there was no previously // set value for the attribute, aOldValue will already be null. oldValue = aOldValue; } -#ifdef MOZ_XBL - if (aComposedDocument) { - RefPtr<nsXBLBinding> binding = GetXBLBinding(); - if (binding) { - binding->AttributeChanged(aName, aNamespaceID, false, aNotify); - } - } -#endif - if (HasElementCreatedFromPrototypeAndHasUnmodifiedL10n() && aNamespaceID == kNameSpaceID_None && (aName == nsGkAtoms::datal10nid || aName == nsGkAtoms::datal10nargs)) { ClearElementCreatedFromPrototypeAndHasUnmodifiedL10n(); if (aComposedDocument) { aComposedDocument->mL10nProtoElements.Remove(this); } } @@ -2512,16 +2389,22 @@ bool Element::ParseAttribute(int32_t aNa } if (aNamespaceID == kNameSpaceID_None) { if (aAttribute == nsGkAtoms::_class || aAttribute == nsGkAtoms::part) { aResult.ParseAtomArray(aValue); return true; } + if (aAttribute == nsGkAtoms::exportparts && + StaticPrefs::layout_css_shadow_parts_enabled()) { + aResult.ParsePartMapping(aValue); + return true; + } + if (aAttribute == nsGkAtoms::id) { // Store id as an atom. id="" means that the element has no id, // not that it has an emptystring as the id. if (aValue.IsEmpty()) { return false; } aResult.ParseAtom(aValue); return true; @@ -2715,25 +2598,16 @@ nsresult Element::UnsetAttr(int32_t aNam } nsAttrValue oldValue; rv = mAttrs.RemoveAttrAt(index, oldValue); NS_ENSURE_SUCCESS(rv, rv); PostIdMaybeChange(aNameSpaceID, aName, nullptr); -#ifdef MOZ_XBL - if (document) { - RefPtr<nsXBLBinding> binding = GetXBLBinding(); - if (binding) { - binding->AttributeChanged(aName, aNameSpaceID, true, aNotify); - } - } -#endif - CustomElementDefinition* definition = GetCustomElementDefinition(); // Only custom element which is in `custom` state could get the // CustomElementDefinition. if (definition && definition->IsInObservedAttributeList(aName)) { nsAutoString ns; nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, ns); RefPtr<nsAtom> oldValueAtom = oldValue.GetAsAtom(); @@ -2843,63 +2717,16 @@ void Element::List(FILE* out, int32_t aI for (; child; child = child->GetNextSibling()) { child->List(out, aIndent + 1); } for (indent = aIndent; --indent >= 0;) fputs(" ", out); } fputs(">\n", out); - -# ifdef MOZ_XBL - Element* nonConstThis = const_cast<Element*>(this); - - // XXX sXBL/XBL2 issue! Owner or current document? - Document* document = OwnerDoc(); - - // Note: not listing nsIAnonymousContentCreator-created content... - - nsBindingManager* bindingManager = document->BindingManager(); - nsINodeList* anonymousChildren = - bindingManager->GetAnonymousNodesFor(nonConstThis); - - if (anonymousChildren) { - uint32_t length = anonymousChildren->Length(); - - for (indent = aIndent; --indent >= 0;) fputs(" ", out); - fputs("anonymous-children<\n", out); - - for (uint32_t i = 0; i < length; ++i) { - nsIContent* child = anonymousChildren->Item(i); - child->List(out, aIndent + 1); - } - - for (indent = aIndent; --indent >= 0;) fputs(" ", out); - fputs(">\n", out); - - bool outHeader = false; - ExplicitChildIterator iter(nonConstThis); - for (nsIContent* child = iter.GetNextChild(); child; - child = iter.GetNextChild()) { - if (!outHeader) { - outHeader = true; - - for (indent = aIndent; --indent >= 0;) fputs(" ", out); - fputs("content-list<\n", out); - } - - child->List(out, aIndent + 1); - } - - if (outHeader) { - for (indent = aIndent; --indent >= 0;) fputs(" ", out); - fputs(">\n", out); - } - } -# endif } void Element::DumpContent(FILE* out, int32_t aIndent, bool aDumpAll) const { int32_t indent; for (indent = aIndent; --indent >= 0;) fputs(" ", out); const nsString& buf = mNodeInfo->QualifiedName(); fputs("<", out); @@ -3909,23 +3736,16 @@ template <class T> void Element::GetCustomInterface(nsGetterAddRefs<T> aResult) { nsCOMPtr<nsISupports> iface = CustomElementRegistry::CallGetCustomInterface( this, NS_GET_TEMPLATE_IID(T)); if (iface) { if (NS_SUCCEEDED(CallQueryInterface(iface, static_cast<T**>(aResult)))) { return; } } - -#ifdef MOZ_XBL - // Otherwise, check the binding manager to see if it implements the interface - // for this element. - OwnerDoc()->BindingManager()->GetBindingImplementation( - this, NS_GET_TEMPLATE_IID(T), aResult); -#endif } void Element::ClearServoData(Document* aDoc) { MOZ_ASSERT(aDoc); if (HasServoData()) { Servo_Element_ClearData(this); } else { UnsetFlags(kAllServoDescendantBits | NODE_NEEDS_FRAME);
--- a/dom/base/Element.h +++ b/dom/base/Element.h @@ -219,34 +219,16 @@ class Element : public FragmentOrElement */ int32_t TabIndex(); /** * Set tabIndex value to this element. */ void SetTabIndex(int32_t aTabIndex, mozilla::ErrorResult& aError); -#ifdef MOZ_XBL - /** - * Sets or unsets an XBL binding for this element. Setting a - * binding on an element that already has a binding will remove the - * old binding. - * - * @param aBinding The binding to bind to this content. If nullptr is - * provided as the argument, then existing binding will be - * removed. - * - * @param aOldBindingManager The old binding manager that contains - * this content if this content was adopted - * to another document. - */ - void SetXBLBinding(nsXBLBinding* aBinding, - nsBindingManager* aOldBindingManager = nullptr); -#endif - /** * Sets the ShadowRoot binding for this element. The contents of the * binding is rendered in place of this node's children. * * @param aShadowRoot The ShadowRoot to be bound to this element. */ void SetShadowRoot(ShadowRoot* aShadowRoot); @@ -1970,32 +1952,16 @@ class Element : public FragmentOrElement // descendants of display: none elements. mozilla::RustCell<ServoNodeData*> mServoData; protected: // Array containing all attributes for this element AttrArray mAttrs; }; -#ifdef MOZ_XBL -class RemoveFromBindingManagerRunnable : public mozilla::Runnable { - public: - RemoveFromBindingManagerRunnable(nsBindingManager* aManager, - nsIContent* aContent, Document* aDoc); - - NS_IMETHOD Run() override; - - private: - virtual ~RemoveFromBindingManagerRunnable(); - RefPtr<nsBindingManager> mManager; - RefPtr<nsIContent> mContent; - RefPtr<Document> mDoc; -}; -#endif - NS_DEFINE_STATIC_IID_ACCESSOR(Element, NS_ELEMENT_IID) inline bool Element::HasAttr(int32_t aNameSpaceID, const nsAtom* aName) const { NS_ASSERTION(nullptr != aName, "must have attribute name"); NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "must have a real namespace ID!"); return mAttrs.IndexOfAttr(aName, aNameSpaceID) >= 0;
--- a/dom/base/FragmentOrElement.cpp +++ b/dom/base/FragmentOrElement.cpp @@ -64,21 +64,16 @@ # include "nsXULElement.h" #endif /* MOZ_XUL */ #include "nsFrameSelection.h" #ifdef DEBUG # include "nsRange.h" #endif #include "nsFrameLoader.h" -#ifdef MOZ_XBL -# include "nsXBLPrototypeBinding.h" -# include "nsBindingManager.h" -# include "nsXBLBinding.h" -#endif #include "nsPIDOMWindow.h" #include "nsSVGUtils.h" #include "nsLayoutUtils.h" #include "nsGkAtoms.h" #include "nsContentUtils.h" #include "nsTextFragment.h" #include "nsContentCID.h" #include "nsWindowSizes.h" @@ -679,22 +674,16 @@ void FragmentOrElement::nsExtendedDOMSlo aCb.NoteXPCOMChild(mControllers); NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mExtendedSlots->mLabelsList"); aCb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsINodeList*, mLabelsList)); NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mExtendedSlots->mShadowRoot"); aCb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mShadowRoot)); -#ifdef MOZ_XBL - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mExtendedSlots->mXBLBinding"); - aCb.NoteNativeChild(mXBLBinding, - NS_CYCLE_COLLECTION_PARTICIPANT(nsXBLBinding)); -#endif - if (mCustomElementData) { mCustomElementData->Traverse(aCb); } } size_t FragmentOrElement::nsExtendedDOMSlots::SizeOfExcludingThis( MallocSizeOf aMallocSizeOf) const { size_t n = @@ -718,24 +707,16 @@ size_t FragmentOrElement::nsExtendedDOMS if (mLabelsList) { n += mLabelsList->SizeOfIncludingThis(aMallocSizeOf); } // mShadowRoot should be handled during normal DOM tree memory reporting, just // like kids, siblings, etc. -#ifdef MOZ_XBL - // We don't seem to have memory reporting for nsXBLBinding. At least - // report the memory it's using directly. - if (mXBLBinding) { - n += aMallocSizeOf(mXBLBinding); - } -#endif - if (mCustomElementData) { n += mCustomElementData->SizeOfIncludingThis(aMallocSizeOf); } return n; } FragmentOrElement::FragmentOrElement( @@ -1086,24 +1067,16 @@ bool nsIContent::IsFocusableInternal(int return false; } bool FragmentOrElement::IsLink(nsIURI** aURI) const { *aURI = nullptr; return false; } -#ifdef MOZ_XBL -nsXBLBinding* FragmentOrElement::DoGetXBLBinding() const { - MOZ_ASSERT(HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)); - const nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots(); - return slots ? slots->mXBLBinding.get() : nullptr; -} -#endif - nsIContent* nsIContent::GetContainingShadowHost() const { if (mozilla::dom::ShadowRoot* shadow = GetContainingShadow()) { return shadow->GetHost(); } return nullptr; } void nsIContent::SetAssignedSlot(HTMLSlotElement* aSlot) { @@ -1164,22 +1137,16 @@ void FragmentOrElement::DestroyContent() // around the flattened tree. // // TODO(emilio): I suspect this can be asserted against instead, with a bit of // effort to avoid calling Document::Destroy with a shell... if (IsElement()) { AsElement()->ClearServoData(); } -#ifdef MOZ_XBL - Document* document = OwnerDoc(); - document->BindingManager()->RemovedFromDocument(this, document, - nsBindingManager::eRunDtor); -#endif - #ifdef DEBUG uint32_t oldChildCount = GetChildCount(); #endif for (nsIContent* child = GetFirstChild(); child; child = child->GetNextSibling()) { child->DestroyContent(); MOZ_ASSERT(child->GetParent() == this, @@ -1375,22 +1342,16 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Fr unbind the child nodes. } */ if (ShadowRoot* shadowRoot = tmp->GetShadowRoot()) { shadowRoot->Unbind(); tmp->ExtendedDOMSlots()->mShadowRoot = nullptr; } -#ifdef MOZ_XBL - Document* doc = tmp->OwnerDoc(); - doc->BindingManager()->RemovedFromDocument(tmp, doc, - nsBindingManager::eDoNotRunDtor); -#endif - NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(FragmentOrElement) void FragmentOrElement::MarkNodeChildren(nsINode* aNode) { JSObject* o = GetJSObjectChild(aNode); if (o) { JS::ExposeObjectToActiveJS(o); @@ -1605,42 +1566,32 @@ static bool ShouldClearPurple(nsIContent // with a frame in a document which has currently active presshell, // we can act as if it was optimizable. When the primary frame dies, aNode // will end up to the purple buffer because of the refcount change. bool NodeHasActiveFrame(Document* aCurrentDoc, nsINode* aNode) { return aCurrentDoc->GetPresShell() && aNode->IsElement() && aNode->AsElement()->GetPrimaryFrame(); } -#ifdef MOZ_XBL -bool OwnedByBindingManager(Document* aCurrentDoc, nsINode* aNode) { - return aNode->IsElement() && aNode->AsElement()->GetXBLBinding(); -} -#endif - // CanSkip checks if aNode is known-live, and if it is, returns true. If aNode // is in a known-live DOM tree, CanSkip may also remove other objects from // purple buffer and unmark event listeners and user data. If the root of the // DOM tree is a document, less optimizations are done since checking the // liveness of the current document is usually fast and we don't want slow down // such common cases. bool FragmentOrElement::CanSkip(nsINode* aNode, bool aRemovingAllowed) { // Don't try to optimize anything during shutdown. if (nsCCUncollectableMarker::sGeneration == 0) { return false; } bool unoptimizable = aNode->UnoptimizableCCNode(); Document* currentDoc = aNode->GetComposedDoc(); if (currentDoc && IsCertainlyAliveNode(aNode, currentDoc) && - (!unoptimizable || NodeHasActiveFrame(currentDoc, aNode) -#ifdef MOZ_XBL - || OwnedByBindingManager(currentDoc, aNode) -#endif - )) { + (!unoptimizable || NodeHasActiveFrame(currentDoc, aNode))) { MarkNodeChildren(aNode); return true; } if (unoptimizable) { return false; } @@ -1833,20 +1784,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_ } else { NS_IMPL_CYCLE_COLLECTION_DESCRIBE(FragmentOrElement, tmp->mRefCnt.get()) } if (!nsIContent::Traverse(tmp, cb)) { return NS_SUCCESS_INTERRUPTED_TRAVERSE; } -#ifdef MOZ_XBL - tmp->OwnerDoc()->BindingManager()->Traverse(tmp, cb); -#endif - // Check that whenever we have effect properties, MayHaveAnimations is set. #ifdef DEBUG nsAtom** effectProps = EffectSet::GetEffectSetPropertyAtoms(); for (uint32_t i = 0; effectProps[i]; ++i) { MOZ_ASSERT_IF(tmp->GetProperty(effectProps[i]), tmp->MayHaveAnimations()); } #endif
--- a/dom/base/FragmentOrElement.h +++ b/dom/base/FragmentOrElement.h @@ -15,19 +15,16 @@ #include "mozilla/Attributes.h" #include "mozilla/MemoryReporting.h" #include "mozilla/UniquePtr.h" #include "nsCycleCollectionParticipant.h" // NS_DECL_CYCLE_* #include "nsIContent.h" // base class #include "nsIHTMLCollection.h" #include "nsDataHashtable.h" -#ifdef MOZ_XBL -# include "nsXBLBinding.h" -#endif class ContentUnbinder; class nsContentList; class nsLabelsNodeList; class nsDOMAttributeMap; class nsDOMTokenList; class nsIControllers; class nsICSSDeclaration; @@ -96,19 +93,16 @@ class FragmentOrElement : public nsICont mozilla::ErrorResult& aError) override; // nsIContent interface methods virtual already_AddRefed<nsINodeList> GetChildren(uint32_t aFilter) override; virtual const nsTextFragment* GetText() override; virtual uint32_t TextLength() const override; virtual bool TextIsOnlyWhitespace() override; virtual bool ThreadSafeTextIsOnlyWhitespace() const override; -#ifdef MOZ_XBL - virtual nsXBLBinding* DoGetXBLBinding() const override; -#endif virtual bool IsLink(nsIURI** aURI) const override; virtual void DestroyContent() override; virtual void SaveSubtreeState() override; nsIHTMLCollection* Children(); uint32_t ChildElementCount() { return Children()->Length(); } @@ -191,23 +185,16 @@ class FragmentOrElement : public nsICont */ RefPtr<nsLabelsNodeList> mLabelsList; /** * ShadowRoot bound to the element. */ RefPtr<ShadowRoot> mShadowRoot; -#ifdef MOZ_XBL - /** - * XBL binding installed on the element. - */ - RefPtr<nsXBLBinding> mXBLBinding; -#endif - /** * Web components custom element data. */ RefPtr<CustomElementData> mCustomElementData; }; class nsDOMSlots : public nsIContent::nsContentSlots { public:
--- a/dom/base/IDTracker.cpp +++ b/dom/base/IDTracker.cpp @@ -5,20 +5,16 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "IDTracker.h" #include "mozilla/Encoding.h" #include "nsContentUtils.h" #include "nsIURI.h" #include "nsIReferrerInfo.h" -#ifdef MOZ_XBL -# include "nsBindingManager.h" -# include "nsXBLPrototypeBinding.h" -#endif #include "nsEscape.h" #include "nsCycleCollectionParticipant.h" namespace mozilla { namespace dom { static DocumentOrShadowRoot* DocOrShadowFromContent(nsIContent& aContent) { ShadowRoot* shadow = aContent.GetContainingShadow(); @@ -60,63 +56,28 @@ void IDTracker::ResetToURIFragmentID(nsI nsresult rv = encoding->DecodeWithoutBOMHandling(refPart, ref); if (NS_FAILED(rv) || ref.IsEmpty()) { return; } rv = NS_OK; nsIContent* bindingParent = aFromContent->GetBindingParent(); if (bindingParent && !aFromContent->IsInShadowTree()) { -#ifdef MOZ_XBL - nsXBLBinding* binding = bindingParent->GetXBLBinding(); - if (!binding) { -#endif - // This happens, for example, if aFromContent is part of the content - // inserted by a call to Document::InsertAnonymousContent, which we - // also want to handle. (It also happens for <use>'s anonymous - // content etc.) - Element* anonRoot = - doc->GetAnonRootIfInAnonymousContentContainer(aFromContent); - if (anonRoot) { - mElement = nsContentUtils::MatchElementId(anonRoot, ref); - // We don't have watching working yet for anonymous content, so bail out - // here. - return; - } -#ifdef MOZ_XBL - } else { - bool isEqualExceptRef; - rv = aURI->EqualsExceptRef(binding->PrototypeBinding()->DocURI(), - &isEqualExceptRef); - if (NS_SUCCEEDED(rv) && isEqualExceptRef) { - // XXX sXBL/XBL2 issue - // Our content is an anonymous XBL element from a binding inside the - // same document that the referenced URI points to. In order to avoid - // the risk of ID collisions we restrict ourselves to anonymous - // elements from this binding; specifically, URIs that are relative to - // the binding document should resolve to the copy of the target - // element that has been inserted into the bound document. - // If the URI points to a different document we don't need this - // restriction. - nsINodeList* anonymousChildren = - doc->BindingManager()->GetAnonymousNodesFor(bindingParent); - - if (anonymousChildren) { - uint32_t length = anonymousChildren->Length(); - for (uint32_t i = 0; i < length && !mElement; ++i) { - mElement = - nsContentUtils::MatchElementId(anonymousChildren->Item(i), ref); - } - } - - // We don't have watching working yet for XBL, so bail out here. - return; - } + // This happens, for example, if aFromContent is part of the content + // inserted by a call to Document::InsertAnonymousContent, which we + // also want to handle. (It also happens for <use>'s anonymous + // content etc.) + Element* anonRoot = + doc->GetAnonRootIfInAnonymousContentContainer(aFromContent); + if (anonRoot) { + mElement = nsContentUtils::MatchElementId(anonRoot, ref); + // We don't have watching working yet for anonymous content, so bail out + // here. + return; } -#endif } bool isEqualExceptRef; rv = aURI->EqualsExceptRef(doc->GetDocumentURI(), &isEqualExceptRef); if (NS_FAILED(rv) || !isEqualExceptRef) { RefPtr<Document::ExternalResourceLoad> load; doc = doc->RequestExternalResource(aURI, aReferrerInfo, aFromContent, getter_AddRefs(load));
--- a/dom/base/MutationObservers.cpp +++ b/dom/base/MutationObservers.cpp @@ -18,19 +18,16 @@ #include "mozilla/EventListenerManager.h" #include "nsIXPConnect.h" #include "PLDHashTable.h" #include "nsCOMArray.h" #include "nsPIDOMWindow.h" #ifdef MOZ_XUL # include "nsXULElement.h" #endif -#ifdef MOZ_XBL -# include "nsBindingManager.h" -#endif #include "nsGenericHTMLElement.h" #include "mozilla/AnimationTarget.h" #include "mozilla/Assertions.h" #include "mozilla/ErrorResult.h" #include "mozilla/dom/Animation.h" #include "mozilla/dom/KeyframeEffect.h" #include "mozilla/PresShell.h" #include "nsWrapperCacheInlines.h" @@ -51,24 +48,19 @@ enum class IsRemoveNotification { #ifdef DEBUG # define COMPOSED_DOC_DECL \ const bool wasInComposedDoc = !!node->GetComposedDoc(); #else # define COMPOSED_DOC_DECL #endif -#ifdef MOZ_XBL -# define CALL_BINDING_MANAGER(func_, params_) \ - doc->BindingManager()->func_ params_ -#else -# define CALL_BINDING_MANAGER(func_, params_) \ - do { \ - } while (0) -#endif +#define CALL_BINDING_MANAGER(func_, params_) \ + do { \ + } while (0) // This macro expects the ownerDocument of content_ to be in scope as // |Document* doc| #define IMPL_MUTATION_NOTIFICATION(func_, content_, params_, remove_) \ PR_BEGIN_MACRO \ bool needsEnterLeave = doc->MayHaveDOMMutationObservers(); \ if (needsEnterLeave) { \ nsDOMMutationObserver::EnterMutationHandling(); \
--- a/dom/base/ShadowRoot.cpp +++ b/dom/base/ShadowRoot.cpp @@ -7,19 +7,16 @@ #include "mozilla/Preferences.h" #include "mozilla/dom/BindContext.h" #include "mozilla/dom/ShadowRoot.h" #include "mozilla/dom/DocumentFragment.h" #include "ChildIterator.h" #include "nsContentUtils.h" #include "nsIStyleSheetLinkingElement.h" #include "nsWindowSizes.h" -#ifdef MOZ_XBL -# include "nsXBLPrototypeBinding.h" -#endif #include "mozilla/dom/DirectionalityUtils.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/HTMLSlotElement.h" #include "mozilla/dom/TreeOrderedArrayInlines.h" #include "mozilla/EventDispatcher.h" #include "mozilla/IdentifierMapEntry.h" #include "mozilla/PresShell.h" #include "mozilla/PresShellInlines.h"
--- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -520,19 +520,16 @@ LOCAL_INCLUDES += [ '/layout/xul', '/netwerk/base', '/netwerk/url-classifier', '/security/manager/ssl', '/widget', '/xpcom/ds', ] -if CONFIG['MOZ_XBL']: - LOCAL_INCLUDES += ['/dom/xbl'] - if CONFIG['MOZ_WEBRTC']: LOCAL_INCLUDES += [ '/netwerk/sctp/datachannel', ] include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul'
--- a/dom/base/nsAttrValue.cpp +++ b/dom/base/nsAttrValue.cpp @@ -15,16 +15,17 @@ #include "nsAttrValue.h" #include "nsAttrValueInlines.h" #include "nsAtom.h" #include "nsUnicharUtils.h" #include "mozilla/CORSMode.h" #include "mozilla/MemoryReporting.h" #include "mozilla/ServoBindingTypes.h" #include "mozilla/ServoUtils.h" +#include "mozilla/ShadowParts.h" #include "mozilla/DeclarationBlock.h" #include "nsContentUtils.h" #include "nsReadableUtils.h" #include "nsHTMLCSSStyleSheet.h" #include "nsStyledElement.h" #include "nsIURI.h" #include "mozilla/dom/Document.h" #include "ReferrerInfo.h" @@ -276,16 +277,17 @@ void nsAttrValue::SetTo(const nsAttrValu case ePercent: { cont->mDoubleValue = otherCont->mDoubleValue; break; } case eColor: { cont->mValue.mColor = otherCont->mValue.mColor; break; } + case eShadowParts: case eCSSDeclaration: { MOZ_CRASH("These should be refcounted!"); } case eURL: { NS_ADDREF(cont->mValue.mURL = otherCont->mValue.mURL); break; } case eAtomArray: { @@ -296,19 +298,20 @@ void nsAttrValue::SetTo(const nsAttrValu } break; } case eDoubleValue: { cont->mDoubleValue = otherCont->mDoubleValue; break; } case eIntMarginValue: { - if (otherCont->mValue.mIntMargin) + if (otherCont->mValue.mIntMargin) { cont->mValue.mIntMargin = new nsIntMargin(*otherCont->mValue.mIntMargin); + } break; } default: { if (IsSVGType(otherCont->mType)) { // All SVG types are just pointers to classes and will therefore have // the same size so it doesn't really matter which one we assign cont->mValue.mSVGLength = otherCont->mValue.mSVGLength; } else { @@ -1150,24 +1153,35 @@ void nsAttrValue::ParseAtomArray(const n } SetMiscAtomOrString(&aValue); } void nsAttrValue::ParseStringOrAtom(const nsAString& aValue) { uint32_t len = aValue.Length(); // Don't bother with atoms if it's an empty string since - // we can store those efficently anyway. + // we can store those efficiently anyway. if (len && len <= NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM) { ParseAtom(aValue); } else { SetTo(aValue); } } +void nsAttrValue::ParsePartMapping(const nsAString& aValue) { + ResetIfSet(); + MiscContainer* cont = EnsureEmptyMiscContainer(); + + cont->mType = eShadowParts; + cont->mValue.mShadowParts = new ShadowParts(ShadowParts::Parse(aValue)); + NS_ADDREF(cont); + SetMiscAtomOrString(&aValue); + MOZ_ASSERT(cont->mValue.mRefCount == 1); +} + void nsAttrValue::SetIntValueAndType(int32_t aValue, ValueType aType, const nsAString* aStringValue) { if (aStringValue || aValue > NS_ATTRVALUE_INTEGERTYPE_MAXVALUE || aValue < NS_ATTRVALUE_INTEGERTYPE_MINVALUE) { MiscContainer* cont = EnsureEmptyMiscContainer(); switch (aType) { case eInteger: { cont->mValue.mInteger = aValue; @@ -1735,16 +1749,22 @@ MiscContainer* nsAttrValue::ClearMiscCon switch (cont->mType) { case eCSSDeclaration: { MOZ_ASSERT(cont->mValue.mRefCount == 1); cont->Release(); cont->Evict(); NS_RELEASE(cont->mValue.mCSSDeclaration); break; } + case eShadowParts: { + MOZ_ASSERT(cont->mValue.mRefCount == 1); + cont->Release(); + delete cont->mValue.mShadowParts; + break; + } case eURL: { NS_RELEASE(cont->mValue.mURL); break; } case eAtomArray: { delete cont->mValue.mAtomArray; break; }
--- a/dom/base/nsAttrValue.h +++ b/dom/base/nsAttrValue.h @@ -96,16 +96,20 @@ class nsAttrValue { // Values below here won't matter, they'll be always stored in the 'misc' // struct. eCSSDeclaration = 0x10, eURL, eImage, eAtomArray, eDoubleValue, eIntMarginValue, + // eShadowParts is refcounted in the misc container, as we do copy attribute + // values quite a bit (for example to process style invalidation), and the + // underlying value could get expensive to copy. + eShadowParts, eSVGIntegerPair, eSVGTypesBegin = eSVGIntegerPair, eSVGOrient, eSVGLength, eSVGLengthList, eSVGNumberList, eSVGNumberPair, eSVGPathData, @@ -252,16 +256,23 @@ class nsAttrValue { */ bool Contains(const nsAString& aValue) const; void ParseAtom(const nsAString& aValue); void ParseAtomArray(const nsAString& aValue); void ParseStringOrAtom(const nsAString& aValue); /** + * Parses an exportparts attribute. + * + * https://drafts.csswg.org/css-shadow-parts/#parsing-mapping-list + */ + void ParsePartMapping(const nsAString&); + + /** * Structure for a mapping from int (enum) values to strings. When you use * it you generally create an array of them. * Instantiate like this: * EnumTable myTable[] = { * { "string1", 1 }, * { "string2", 2 }, * { nullptr, 0 } * }
--- a/dom/base/nsAttrValueInlines.h +++ b/dom/base/nsAttrValueInlines.h @@ -9,16 +9,20 @@ #include <stdint.h> #include "nsAttrValue.h" #include "mozilla/Atomics.h" #include "mozilla/Attributes.h" #include "mozilla/ServoUtils.h" +namespace mozilla { +class ShadowParts; +} + struct MiscContainer final { typedef nsAttrValue::ValueType ValueType; ValueType mType; // mStringBits points to either nsAtom* or nsStringBuffer* and is used when // mType isn't eCSSDeclaration. // Note eStringBase and eAtomBase is used also to handle the type of // mStringBits. @@ -36,16 +40,17 @@ struct MiscContainer final { union { int32_t mInteger; nscolor mColor; uint32_t mEnumValue; mozilla::DeclarationBlock* mCSSDeclaration; nsIURI* mURL; mozilla::AtomArray* mAtomArray; nsIntMargin* mIntMargin; + const mozilla::ShadowParts* mShadowParts; const mozilla::SVGAnimatedIntegerPair* mSVGAnimatedIntegerPair; const mozilla::SVGAnimatedLength* mSVGLength; const mozilla::SVGAnimatedNumberPair* mSVGAnimatedNumberPair; const mozilla::SVGAnimatedOrient* mSVGAnimatedOrient; const mozilla::SVGAnimatedPreserveAspectRatio* mSVGAnimatedPreserveAspectRatio; const mozilla::SVGAnimatedViewBox* mSVGAnimatedViewBox; const mozilla::SVGLengthList* mSVGLengthList; @@ -90,17 +95,18 @@ struct MiscContainer final { MOZ_ASSERT(NS_IsMainThread()); mStringBits = aBits; } inline bool IsRefCounted() const { // Nothing stops us from refcounting (and sharing) other types of // MiscContainer (except eDoubleValue types) but there's no compelling // reason to. - return mType == nsAttrValue::eCSSDeclaration; + return mType == nsAttrValue::eCSSDeclaration || + mType == nsAttrValue::eShadowParts; } inline int32_t AddRef() { MOZ_ASSERT(IsRefCounted()); return ++mValue.mRefCount; } inline int32_t Release() {
--- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -111,19 +111,16 @@ #include "mozilla/TextControlState.h" #include "mozilla/TextEditor.h" #include "mozilla/TextEvents.h" #include "nsArrayUtils.h" #include "nsAString.h" #include "nsAttrName.h" #include "nsAttrValue.h" #include "nsAttrValueInlines.h" -#ifdef MOZ_XBL -# include "nsBindingManager.h" -#endif #include "nsCanvasFrame.h" #include "nsCaret.h" #include "nsCCUncollectableMarker.h" #include "nsCharSeparatedTokenizer.h" #include "nsCOMPtr.h" #include "nsContentCreatorFunctions.h" #include "nsContentDLF.h" #include "nsContentList.h" @@ -2146,23 +2143,17 @@ bool nsContentUtils::ThreadsafeIsSystemC return ccjscx->IsSystemCaller(); } // static bool nsContentUtils::LookupBindingMember( JSContext* aCx, nsIContent* aContent, JS::Handle<jsid> aId, JS::MutableHandle<JS::PropertyDescriptor> aDesc) { -#ifdef MOZ_XBL - nsXBLBinding* binding = aContent->GetXBLBinding(); - if (!binding) return true; - return binding->LookupMember(aCx, aId, aDesc); -#else return true; -#endif } // static nsINode* nsContentUtils::GetCrossDocParentNode(nsINode* aChild) { MOZ_ASSERT(aChild, "The child is null!"); nsINode* parent = aChild->GetParentNode(); if (parent && parent->IsContent() && aChild->IsContent()) {
--- a/dom/base/nsFocusManager.cpp +++ b/dom/base/nsFocusManager.cpp @@ -30,19 +30,16 @@ #include "mozilla/dom/Document.h" #include "mozilla/dom/Selection.h" #include "nsXULPopupManager.h" #include "nsMenuPopupFrame.h" #include "nsIScriptObjectPrincipal.h" #include "nsIPrincipal.h" #include "nsIObserverService.h" #include "nsIObjectFrame.h" -#ifdef MOZ_XBL -# include "nsBindingManager.h" -#endif #include "BrowserChild.h" #include "nsFrameLoader.h" #include "nsHTMLDocument.h" #include "nsNumberControlFrame.h" #include "nsNetUtil.h" #include "nsRange.h" #include "mozilla/AccessibleCaretEventHub.h"
--- a/dom/base/nsGlobalWindowInner.cpp +++ b/dom/base/nsGlobalWindowInner.cpp @@ -179,21 +179,16 @@ # include "nsIPrintSettingsService.h" # include "nsIWebBrowserPrint.h" #endif #include "nsWindowRoot.h" #include "nsNetCID.h" #include "nsIArray.h" -#ifdef MOZ_XBL -# include "nsBindingManager.h" -# include "nsXBLService.h" -#endif - #include "nsIDragService.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/Selection.h" #include "nsFrameLoader.h" #include "nsISupportsPrimitives.h" #include "nsXPCOMCID.h" #include "mozilla/Logging.h" #include "prenv.h" @@ -2003,23 +1998,16 @@ nsresult nsGlobalWindowInner::PostHandle // XXX The WebVR 1.1 spec does not define which of multiple VR // presenting VR displays will be chosen during navigation. // As the underlying platform VR API's currently only allow a single // VR display, it is safe to choose the first VR display for now. break; } } -#ifdef MOZ_XBL - // Execute bindingdetached handlers before we tear ourselves - // down. - if (mDoc) { - mDoc->BindingManager()->ExecuteDetachedHandlers(); - } -#endif mIsDocumentLoaded = false; } else if (aVisitor.mEvent->mMessage == eLoad && aVisitor.mEvent->IsTrusted()) { // This is page load event since load events don't propagate to |window|. // @see Document::GetEventTargetParent. mIsDocumentLoaded = true; mTimeoutManager->OnDocumentLoaded();
--- a/dom/base/nsGlobalWindowOuter.cpp +++ b/dom/base/nsGlobalWindowOuter.cpp @@ -173,20 +173,16 @@ #include "nsWindowRoot.h" #include "nsNetCID.h" #include "nsIArray.h" #include "nsIDOMXULCommandDispatcher.h" #include "mozilla/GlobalKeyListener.h" -#ifdef MOZ_XBL -# include "nsBindingManager.h" -# include "nsXBLService.h" -#endif #include "nsIDragService.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/Selection.h" #include "nsFrameLoader.h" #include "nsISupportsPrimitives.h" #include "nsXPCOMCID.h" #include "mozilla/Logging.h"
--- a/dom/base/nsIContent.h +++ b/dom/base/nsIContent.h @@ -16,19 +16,16 @@ // Forward declarations class nsAtom; class nsIURI; class nsAttrValue; class nsAttrName; class nsTextFragment; class nsIFrame; -#ifdef MOZ_XBL -class nsXBLBinding; -#endif class nsITextControlElement; namespace mozilla { class EventChainPreVisitor; struct URLExtraData; namespace dom { struct BindContext; class ShadowRoot; @@ -392,33 +389,16 @@ class nsIContent : public nsINode { * * @return the binding parent */ virtual mozilla::dom::Element* GetBindingParent() const { const nsExtendedContentSlots* slots = GetExistingExtendedContentSlots(); return slots ? slots->mBindingParent.get() : nullptr; } -#ifdef MOZ_XBL - /** - * Gets the current XBL binding that is bound to this element. - * - * @return the current binding. - */ - nsXBLBinding* GetXBLBinding() const { - if (!HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) { - return nullptr; - } - - return DoGetXBLBinding(); - } - - virtual nsXBLBinding* DoGetXBLBinding() const = 0; -#endif - /** * Gets the ShadowRoot binding for this element. * * @return The ShadowRoot currently bound to this element. */ inline mozilla::dom::ShadowRoot* GetShadowRoot() const; /**
--- a/dom/base/nsIContentInlines.h +++ b/dom/base/nsIContentInlines.h @@ -4,19 +4,16 @@ * 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 nsIContentInlines_h #define nsIContentInlines_h #include "nsIContent.h" #include "mozilla/dom/Document.h" -#ifdef MOZ_XBL -# include "nsBindingManager.h" -#endif #include "nsContentUtils.h" #include "nsAtom.h" #include "nsIFrame.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/HTMLSlotElement.h" #include "mozilla/dom/ShadowRoot.h" inline bool nsINode::IsUAWidget() const { @@ -115,32 +112,16 @@ static inline nsINode* GetFlattenedTreeP } if (auto* shadowRoot = mozilla::dom::ShadowRoot::FromNode(parentAsContent)) { return shadowRoot->GetHost(); } } -#ifdef MOZ_XBL - if (content->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) || - parent->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) { - if (nsIContent* xblInsertionPoint = content->GetXBLInsertionPoint()) { - return xblInsertionPoint->GetParent(); - } - - if (parent->OwnerDoc()->BindingManager()->GetBindingWithContent( - parentAsContent)) { - // This is an unassigned node child of the bound element, so it isn't part - // of the flat tree. - return nullptr; - } - } -#endif - MOZ_ASSERT(!parentAsContent->IsActiveChildrenElement(), "<xbl:children> isn't in the flattened tree"); // Common case. return parent; } inline nsINode* nsINode::GetFlattenedTreeParentNode() const {
--- a/dom/base/nsINode.cpp +++ b/dom/base/nsINode.cpp @@ -89,21 +89,16 @@ #include "nsObjectLoadingContent.h" #include "nsPIDOMWindow.h" #include "nsPresContext.h" #include "nsString.h" #include "nsStyleConsts.h" #include "nsSVGUtils.h" #include "nsTextNode.h" #include "nsUnicharUtils.h" -#ifdef MOZ_XBL -# include "nsBindingManager.h" -# include "nsXBLBinding.h" -# include "nsXBLPrototypeBinding.h" -#endif #include "nsWindowSizes.h" #include "mozilla/Preferences.h" #include "xpcpublic.h" #include "HTMLLegendElement.h" #include "nsWrapperCacheInlines.h" #include "WrapperFactory.h" #include <algorithm> #include "nsGlobalWindow.h" @@ -531,21 +526,16 @@ void nsINode::LastRelease() { } } #endif nsContentUtils::RemoveListenerManager(this); UnsetFlags(NODE_HAS_LISTENERMANAGER); } -#ifdef MOZ_XBL - NS_ASSERTION( - !Element::FromNode(this) || !Element::FromNode(this)->GetXBLBinding(), - "Node has binding on destruction"); -#endif ReleaseWrapper(this); FragmentOrElement::RemoveBlackMarkedNode(this); } #ifdef DEBUG void nsINode::CheckNotNativeAnonymous() const {
--- a/dom/base/nsJSUtils.cpp +++ b/dom/base/nsJSUtils.cpp @@ -25,19 +25,16 @@ #include "nsCOMPtr.h" #include "nsIScriptSecurityManager.h" #include "nsPIDOMWindow.h" #include "GeckoProfiler.h" #include "nsJSPrincipals.h" #include "xpcpublic.h" #include "nsContentUtils.h" #include "nsGlobalWindow.h" -#ifdef MOZ_XBL -# include "nsXBLPrototypeBinding.h" -#endif #include "mozilla/CycleCollectedJSContext.h" #include "mozilla/StaticPrefs_browser.h" #include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/Date.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/ScriptSettings.h" #include "mozilla/Utf8.h" // mozilla::Utf8Unit @@ -615,41 +612,16 @@ bool nsJSUtils::GetScopeChainForElement( if (!AddScopeChainItem(aCx, cur, aScopeChain)) { return false; } } return true; } -#ifdef MOZ_XBL -/* static */ -bool nsJSUtils::GetScopeChainForXBL( - JSContext* aCx, Element* aElement, - const nsXBLPrototypeBinding& aProtoBinding, - JS::MutableHandleVector<JSObject*> aScopeChain) { - if (!aElement) { - return true; - } - - if (!aProtoBinding.SimpleScopeChain()) { - return GetScopeChainForElement(aCx, aElement, aScopeChain); - } - - if (!AddScopeChainItem(aCx, aElement, aScopeChain)) { - return false; - } - - if (!AddScopeChainItem(aCx, aElement->OwnerDoc(), aScopeChain)) { - return false; - } - return true; -} -#endif - /* static */ void nsJSUtils::ResetTimeZone() { JS::ResetTimeZone(); } /* static */ bool nsJSUtils::DumpEnabled() { #if defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP) return true; #else
--- a/dom/base/nsJSUtils.h +++ b/dom/base/nsJSUtils.h @@ -236,29 +236,16 @@ class nsJSUtils { static nsresult ModuleEvaluate(JSContext* aCx, JS::Handle<JSObject*> aModule); // Returns false if an exception got thrown on aCx. Passing a null // aElement is allowed; that wil produce an empty aScopeChain. static bool GetScopeChainForElement( JSContext* aCx, mozilla::dom::Element* aElement, JS::MutableHandleVector<JSObject*> aScopeChain); -#ifdef MOZ_XBL - // Returns a scope chain suitable for XBL execution. - // - // This is by default GetScopeChainForElemenet, but will be different if the - // <binding> element had the simpleScopeChain attribute. - // - // This is to prevent footguns like bug 1446342. - static bool GetScopeChainForXBL( - JSContext* aCx, mozilla::dom::Element* aBoundElement, - const nsXBLPrototypeBinding& aProtoBinding, - JS::MutableHandleVector<JSObject*> aScopeChain); -#endif - static void ResetTimeZone(); static bool DumpEnabled(); }; inline void AssignFromStringBuffer(nsStringBuffer* buffer, size_t len, nsAString& dest) { buffer->ToString(len, dest);
--- a/dom/base/nsNameSpaceManager.cpp +++ b/dom/base/nsNameSpaceManager.cpp @@ -16,19 +16,16 @@ #include "nsAtom.h" #include "nsCOMArray.h" #include "nsContentCreatorFunctions.h" #include "nsGkAtoms.h" #include "mozilla/dom/Document.h" #include "nsString.h" #include "mozilla/dom/NodeInfo.h" #include "mozilla/ClearOnShutdown.h" -#ifdef MOZ_XBL -# include "mozilla/dom/XBLChildrenElement.h" -#endif #include "mozilla/dom/Element.h" #include "mozilla/Preferences.h" using namespace mozilla; using namespace mozilla::dom; static const char* kPrefSVGDisabled = "svg.disabled"; static const char* kPrefMathMLDisabled = "mathml.disabled"; @@ -200,22 +197,16 @@ nsresult NS_NewElement(Element** aResult return NS_NewSVGElement(aResult, ni.forget(), aFromParser); } RefPtr<mozilla::dom::NodeInfo> genericXMLNI = ni->NodeInfoManager()->GetNodeInfo(ni->NameAtom(), ni->GetPrefixAtom(), kNameSpaceID_disabled_SVG, ni->NodeType(), ni->GetExtraName()); return NS_NewXMLElement(aResult, genericXMLNI.forget()); } -#ifdef MOZ_XBL - if (ns == kNameSpaceID_XBL && ni->Equals(nsGkAtoms::children)) { - NS_ADDREF(*aResult = new XBLChildrenElement(ni.forget())); - return NS_OK; - } -#endif return NS_NewXMLElement(aResult, ni.forget()); } bool nsNameSpaceManager::HasElementCreator(int32_t aNameSpaceID) { return aNameSpaceID == kNameSpaceID_XHTML || #ifdef MOZ_XUL aNameSpaceID == kNameSpaceID_XUL ||
--- a/dom/base/nsNodeInfoManager.cpp +++ b/dom/base/nsNodeInfoManager.cpp @@ -20,19 +20,16 @@ #include "nsAtom.h" #include "nsIPrincipal.h" #include "nsIURI.h" #include "nsContentUtils.h" #include "nsReadableUtils.h" #include "nsGkAtoms.h" #include "nsComponentManagerUtils.h" #include "nsLayoutStatics.h" -#ifdef MOZ_XBL -# include "nsBindingManager.h" -#endif #include "nsHashKeys.h" #include "nsCCUncollectableMarker.h" #include "nsNameSpaceManager.h" #include "nsWindowSizes.h" using namespace mozilla; using mozilla::dom::NodeInfo; @@ -55,37 +52,30 @@ nsNodeInfoManager::nsNodeInfoManager() MOZ_LOG(gNodeInfoManagerLeakPRLog, LogLevel::Debug, ("NODEINFOMANAGER %p created", this)); } nsNodeInfoManager::~nsNodeInfoManager() { // Note: mPrincipal may be null here if we never got inited correctly mPrincipal = nullptr; -#ifdef MOZ_XBL - mBindingManager = nullptr; -#endif - if (gNodeInfoManagerLeakPRLog) MOZ_LOG(gNodeInfoManagerLeakPRLog, LogLevel::Debug, ("NODEINFOMANAGER %p destroyed", this)); nsLayoutStatics::Release(); } NS_IMPL_CYCLE_COLLECTION_CLASS(nsNodeInfoManager) NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsNodeInfoManager) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsNodeInfoManager) if (tmp->mNonDocumentNodeInfos) { NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mDocument) } -#ifdef MOZ_XBL - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBindingManager) -#endif NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsNodeInfoManager, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsNodeInfoManager, Release) NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsNodeInfoManager) if (tmp->mDocument) { return NS_CYCLE_COLLECTION_PARTICIPANT(mozilla::dom::Document) @@ -107,40 +97,28 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_B } NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END nsresult nsNodeInfoManager::Init(mozilla::dom::Document* aDocument) { MOZ_ASSERT(!mPrincipal, "Being inited when we already have a principal?"); mPrincipal = NullPrincipal::CreateWithoutOriginAttributes(); -#ifdef MOZ_XBL - if (aDocument) { - mBindingManager = new nsBindingManager(aDocument); - } -#endif - mDefaultPrincipal = mPrincipal; mDocument = aDocument; if (gNodeInfoManagerLeakPRLog) MOZ_LOG(gNodeInfoManagerLeakPRLog, LogLevel::Debug, ("NODEINFOMANAGER %p Init document=%p", this, aDocument)); return NS_OK; } void nsNodeInfoManager::DropDocumentReference() { -#ifdef MOZ_XBL - if (mBindingManager) { - mBindingManager->DropDocumentReference(); - } -#endif - // This is probably not needed anymore. for (auto iter = mNodeInfoHash.Iter(); !iter.Done(); iter.Next()) { iter.Data()->mDocument = nullptr; } NS_ASSERTION(!mNonDocumentNodeInfos, "Shouldn't have non-document nodeinfos!"); mDocument = nullptr; @@ -372,19 +350,12 @@ bool nsNodeInfoManager::InternalMathMLEn nsContentUtils::IsSystemPrincipal(mPrincipal)); mMathMLEnabled = Some(conclusion); return conclusion; } void nsNodeInfoManager::AddSizeOfIncludingThis(nsWindowSizes& aSizes) const { aSizes.mDOMOtherSize += aSizes.mState.mMallocSizeOf(this); -#ifdef MOZ_XBL - if (mBindingManager) { - aSizes.mBindingsSize += - mBindingManager->SizeOfIncludingThis(aSizes.mState.mMallocSizeOf); - } -#endif - // Measurement of the following members may be added later if DMD finds it // is worthwhile: // - mNodeInfoHash }
--- a/dom/base/nsNodeInfoManager.h +++ b/dom/base/nsNodeInfoManager.h @@ -14,19 +14,16 @@ #include "mozilla/Attributes.h" // for final #include "mozilla/dom/NodeInfo.h" #include "mozilla/MruCache.h" #include "nsCOMPtr.h" // for member #include "nsCycleCollectionParticipant.h" // for NS_DECL_CYCLE_* #include "nsDataHashtable.h" #include "nsStringFwd.h" -#ifdef MOZ_XBL -class nsBindingManager; -#endif class nsAtom; class nsIPrincipal; class nsWindowSizes; template <class T> struct already_AddRefed; namespace mozilla { namespace dom { @@ -95,20 +92,16 @@ class nsNodeInfoManager final { */ nsIPrincipal* DocumentPrincipal() const { NS_ASSERTION(mPrincipal, "How'd that happen?"); return mPrincipal; } void RemoveNodeInfo(mozilla::dom::NodeInfo* aNodeInfo); -#ifdef MOZ_XBL - nsBindingManager* GetBindingManager() const { return mBindingManager; } -#endif - /** * Returns true if SVG nodes in this document have real SVG semantics. */ bool SVGEnabled() { return mSVGEnabled.valueOr(InternalSVGEnabled()); } /** * Returns true if MathML nodes in this document have real MathML semantics. */ @@ -160,17 +153,14 @@ class nsNodeInfoManager final { nsCOMPtr<nsIPrincipal> mPrincipal; // Never null after Init() succeeds. nsCOMPtr<nsIPrincipal> mDefaultPrincipal; // Never null after Init() succeeds mozilla::dom::NodeInfo* MOZ_NON_OWNING_REF mTextNodeInfo; // WEAK to avoid circular ownership mozilla::dom::NodeInfo* MOZ_NON_OWNING_REF mCommentNodeInfo; // WEAK to avoid circular ownership mozilla::dom::NodeInfo* MOZ_NON_OWNING_REF mDocumentNodeInfo; // WEAK to avoid circular ownership -#ifdef MOZ_XBL - RefPtr<nsBindingManager> mBindingManager; -#endif NodeInfoCache mRecentlyUsedNodeInfos; mozilla::Maybe<bool> mSVGEnabled; // Lazily initialized. mozilla::Maybe<bool> mMathMLEnabled; // Lazily initialized. }; #endif /* nsNodeInfoManager_h___ */
--- a/dom/bindings/moz.build +++ b/dom/bindings/moz.build @@ -88,19 +88,16 @@ LOCAL_INCLUDES += [ '/layout/xul/tree', '/media/mtransport', '/media/webrtc/', '/media/webrtc/signaling/src/common/time_profiling', '/media/webrtc/signaling/src/peerconnection', '/media/webrtc/trunk/', ] -if CONFIG['MOZ_XBL']: - LOCAL_INCLUDES += ['/dom/xbl'] - LOCAL_INCLUDES += ['/third_party/msgpack/include'] DEFINES['GOOGLE_PROTOBUF_NO_RTTI'] = True DEFINES['GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER'] = True UNIFIED_SOURCES += [ 'BindingUtils.cpp', 'CallbackInterface.cpp',
--- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -5507,30 +5507,32 @@ void EventStateManager::RemoveNodeFromCh !aContentRemoved->AsElement()->State().HasState(aState)) { return; } nsCOMPtr<nsIContent>& leaf = aState == NS_EVENT_STATE_HOVER ? mHoverContent : mActiveContent; MOZ_ASSERT(leaf); - // XBL Likes to unbind content without notifying, thus the - // NODE_IS_ANONYMOUS_ROOT check... + // These two NS_ASSERTIONS below can fail for Shadow DOM sometimes, and it's + // not clear how to best handle it, see + // https://github.com/whatwg/html/issues/4795 and bug 1551621. // - // This can also happen for Shadow DOM sometimes, and it's not clear how to - // best handle it, see https://github.com/whatwg/html/issues/4795 and - // bug 1551621. + // The NODE_IS_ANONYMOUS_ROOT is there because XBL used to remove content + // without notifying, but it shouldn't apply to NAC since + // NAC notifies (see NativeAnonymousContentRemoved). NS_ASSERTION(nsContentUtils::ContentIsFlattenedTreeDescendantOf( leaf, aContentRemoved) || - leaf->SubtreeRoot()->HasFlag(NODE_IS_ANONYMOUS_ROOT), + leaf->SubtreeRoot()->HasFlag(NODE_IS_ANONYMOUS_ROOT), "Flat tree and active / hover chain got out of sync"); nsIContent* newLeaf = aContentRemoved->GetFlattenedTreeParent(); - MOZ_ASSERT_IF(newLeaf, newLeaf->IsElement() && - newLeaf->AsElement()->State().HasState(aState)); + MOZ_ASSERT(!newLeaf || newLeaf->IsElement()); + NS_ASSERTION(!newLeaf || newLeaf->AsElement()->State().HasState(aState), + "State got out of sync because of shadow DOM"); if (aNotify) { SetContentState(newLeaf, aState); } else { // We don't update the removed content's state here, since removing NAC // happens from layout and we don't really want to notify at that point or // what not. // // Also, NAC is not observable and NAC being removed will go away soon.
--- a/dom/html/moz.build +++ b/dom/html/moz.build @@ -248,18 +248,15 @@ LOCAL_INCLUDES += [ '/layout/forms', '/layout/generic', '/layout/style', '/layout/tables', '/layout/xul', '/netwerk/base', ] -if CONFIG['MOZ_XBL']: - LOCAL_INCLUDES += ['/dom/xbl'] - FINAL_LIBRARY = 'xul' if CONFIG['MOZ_ANDROID_HLS_SUPPORT']: DEFINES['MOZ_ANDROID_HLS_SUPPORT'] = True if CONFIG['CC_TYPE'] in ('clang', 'gcc'): CXXFLAGS += ['-Wno-error=shadow']
--- a/dom/interfaces/base/nsIRemoteTab.idl +++ b/dom/interfaces/base/nsIRemoteTab.idl @@ -52,17 +52,16 @@ interface nsIRemoteTab : nsISupports readonly attribute uint64_t contentProcessId; /** * The OS level process Id of the related child process. */ readonly attribute int32_t osPid; - readonly attribute boolean hasContentOpener; /** * True if we've previously received layers for this tab when switching to * it. */ readonly attribute boolean hasPresented; /** * Ensures that the content process which has this remote tab has all of the
--- a/dom/ipc/BrowserBridgeParent.cpp +++ b/dom/ipc/BrowserBridgeParent.cpp @@ -227,16 +227,27 @@ IPCResult BrowserBridgeParent::RecvSetIs return IPC_OK(); } IPCResult BrowserBridgeParent::RecvSetEmbedderAccessible( PDocAccessibleParent* aDoc, uint64_t aID) { #ifdef ACCESSIBILITY mEmbedderAccessibleDoc = static_cast<a11y::DocAccessibleParent*>(aDoc); mEmbedderAccessibleID = aID; + if (auto embeddedBrowser = GetBrowserParent()) { + a11y::DocAccessibleParent* childDocAcc = + embeddedBrowser->GetTopLevelDocAccessible(); + if (childDocAcc && !childDocAcc->IsShutdown()) { + // The embedded DocAccessibleParent has already been created. This can + // happen if, for example, an iframe is hidden and then shown or + // an iframe is reflowed by layout. + mEmbedderAccessibleDoc->AddChildDoc(childDocAcc, aID, + /* aCreating */ false); + } + } #endif return IPC_OK(); } void BrowserBridgeParent::ActorDestroy(ActorDestroyReason aWhy) { Destroy(); } } // namespace dom } // namespace mozilla
--- a/dom/ipc/BrowserHost.cpp +++ b/dom/ipc/BrowserHost.cpp @@ -254,27 +254,16 @@ BrowserHost::GetOsPid(int32_t* aOsPid) { if (!mRoot) { *aOsPid = 0; return NS_OK; } *aOsPid = GetContentParent()->Pid(); return NS_OK; } -/* readonly attribute boolean hasContentOpener; */ -NS_IMETHODIMP -BrowserHost::GetHasContentOpener(bool* aHasContentOpener) { - if (!mRoot) { - *aHasContentOpener = false; - return NS_OK; - } - *aHasContentOpener = mRoot->GetHasContentOpener(); - return NS_OK; -} - /* readonly attribute boolean hasPresented; */ NS_IMETHODIMP BrowserHost::GetHasPresented(bool* aHasPresented) { if (!mRoot) { *aHasPresented = false; return NS_OK; } *aHasPresented = mRoot->GetHasPresented();
--- a/dom/ipc/BrowserParent.cpp +++ b/dom/ipc/BrowserParent.cpp @@ -5,16 +5,18 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "base/basictypes.h" #include "BrowserParent.h" #ifdef ACCESSIBILITY # include "mozilla/a11y/DocAccessibleParent.h" +# include "mozilla/a11y/Platform.h" +# include "mozilla/a11y/ProxyAccessibleBase.h" # include "nsAccessibilityService.h" #endif #include "mozilla/BrowserElementParent.h" #include "mozilla/dom/CancelContentJSOptionsBinding.h" #include "mozilla/dom/ChromeMessageSender.h" #include "mozilla/dom/ContentParent.h" #include "mozilla/dom/DataTransfer.h" #include "mozilla/dom/DataTransferItemList.h" @@ -206,17 +208,16 @@ BrowserParent::BrowserParent(ContentPare mCustomCursor{}, mCustomCursorHotspotX(0), mCustomCursorHotspotY(0), mVerifyDropLinks{}, mDocShellIsActive(false), mMarkedDestroying(false), mIsDestroyed(false), mTabSetsCursor(false), - mHasContentOpener(false), mPreserveLayers(false), mRenderLayers(true), mActiveInPriorityManager(false), mHasLayers(false), mHasPresented(false), mIsReadyToHandleInputEvents(false), mIsMouseEnterIntoWidgetEventSuppressed(false), mIsActiveRecordReplayTab(false) { @@ -1168,45 +1169,54 @@ mozilla::ipc::IPCResult BrowserParent::R if (a11y::nsWinUtils::IsWindowEmulationStarted()) { doc->SetEmulatedWindowHandle(parentDoc->GetEmulatedWindowHandle()); } # endif return IPC_OK(); } - a11y::DocAccessibleParent* embedderDoc; - uint64_t embedderID; - Tie(embedderDoc, embedderID) = doc->GetRemoteEmbedder(); - if (embedderDoc) { + if (GetBrowserBridgeParent()) { // Iframe document rendered in a different process to its embedder. // In this case, we don't get aParentDoc and aParentID. MOZ_ASSERT(!aParentDoc && !aParentID); - MOZ_ASSERT(embedderID); doc->SetTopLevelInContentProcess(); # ifdef XP_WIN MOZ_ASSERT(!aDocCOMProxy.IsNull()); RefPtr<IAccessible> proxy(aDocCOMProxy.Get()); doc->SetCOMInterface(proxy); # endif - mozilla::ipc::IPCResult added = embedderDoc->AddChildDoc(doc, embedderID); - if (!added) { -# ifdef DEBUG - return added; -# else - return IPC_OK(); -# endif - } + a11y::ProxyCreated( + doc, a11y::Interfaces::DOCUMENT | a11y::Interfaces::HYPERTEXT); # ifdef XP_WIN - // This *must* be called after AddChildDoc because AddChildDoc - // calls ProxyCreated and WrapperFor will fail before that. + // This *must* be called after ProxyCreated because WrapperFor will fail + // before that. a11y::AccessibleWrap* wrapper = a11y::WrapperFor(doc); MOZ_ASSERT(wrapper); wrapper->SetID(aMsaaID); # endif + a11y::DocAccessibleParent* embedderDoc; + uint64_t embedderID; + Tie(embedderDoc, embedderID) = doc->GetRemoteEmbedder(); + // It's possible the embedder accessible hasn't been set yet; e.g. + // a hidden iframe. In that case, embedderDoc will be null and this will + // be handled when the embedder is set. + if (embedderDoc) { + MOZ_ASSERT(embedderID); + mozilla::ipc::IPCResult added = + embedderDoc->AddChildDoc(doc, embedderID, + /* aCreating */ false); + if (!added) { +# ifdef DEBUG + return added; +# else + return IPC_OK(); +# endif + } + } return IPC_OK(); } else { // null aParentDoc means this document is at the top level in the child // process. That means it makes no sense to get an id for an accessible // that is its parent. MOZ_ASSERT(!aParentID); if (aParentID) { return IPC_FAIL_NO_REASON(this); @@ -3347,22 +3357,16 @@ void BrowserParent::NotifyResolutionChan void BrowserParent::Deprioritize() { if (mActiveInPriorityManager) { ProcessPriorityManager::TabActivityChanged(this, false); mActiveInPriorityManager = false; } } -bool BrowserParent::GetHasContentOpener() { return mHasContentOpener; } - -void BrowserParent::SetHasContentOpener(bool aHasContentOpener) { - mHasContentOpener = aHasContentOpener; -} - bool BrowserParent::StartApzAutoscroll(float aAnchorX, float aAnchorY, nsViewID aScrollId, uint32_t aPresShellId) { if (!AsyncPanZoomEnabled()) { return false; } bool success = false;
--- a/dom/ipc/BrowserParent.h +++ b/dom/ipc/BrowserParent.h @@ -249,17 +249,16 @@ class BrowserParent final : public PBrow } void SetOwnerElement(Element* aElement); void SetBrowserDOMWindow(nsIBrowserDOMWindow* aBrowserDOMWindow) { mBrowserDOMWindow = aBrowserDOMWindow; } - void SetHasContentOpener(bool aHasContentOpener); void SwapFrameScriptsFrom(nsTArray<FrameScriptInfo>& aFrameScripts) { aFrameScripts.SwapElements(mDelayedFrameScripts); } void CacheFrameLoader(nsFrameLoader* aFrameLoader); void Destroy(); @@ -736,18 +735,16 @@ class BrowserParent final : public PBrow bool GetHasLayers(); bool GetRenderLayers(); void SetRenderLayers(bool aRenderLayers); void PreserveLayers(bool aPreserveLayers); void NotifyResolutionChanged(); void Deprioritize(); - bool GetHasContentOpener(); - bool StartApzAutoscroll(float aAnchorX, float aAnchorY, nsViewID aScrollId, uint32_t aPresShellId); void StopApzAutoscroll(nsViewID aScrollId, uint32_t aPresShellId); protected: friend BrowserBridgeParent; friend BrowserHost; @@ -943,18 +940,16 @@ class BrowserParent final : public PBrow bool mMarkedDestroying; // When true, the BrowserParent is invalid and we should not send IPC messages // anymore. bool mIsDestroyed; // True if the cursor changes from the BrowserChild should change the widget // cursor. This happens whenever the cursor is in the tab's region. bool mTabSetsCursor; - bool mHasContentOpener; - // If this flag is set, then the tab's layers will be preserved even when // the tab's docshell is inactive. bool mPreserveLayers; // Holds the most recent value passed to the RenderLayers function. This // does not necessarily mean that the layers have finished rendering // and have uploaded - for that, use mHasLayers. bool mRenderLayers;
--- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -227,16 +227,17 @@ #include "mozilla/StyleSheetInlines.h" #include "nsICaptivePortalService.h" #include "nsIObjectLoadingContent.h" #include "nsIBidiKeyboard.h" #include "nsLayoutStylesheetCache.h" #include "MMPrinter.h" #include "nsStreamUtils.h" #include "nsIAsyncInputStream.h" +#include "xpcpublic.h" #include "mozilla/Sprintf.h" #ifdef MOZ_WEBRTC # include "signaling/src/peerconnection/WebrtcGlobalParent.h" #endif #if defined(XP_MACOSX) @@ -1804,17 +1805,25 @@ bool ContentParent::ShouldKeepProcessAli } // We might want to keep some content processes alive for performance reasons. // e.g. test runs and privileged content process for some about: pages. // We don't want to alter behavior if the pref is not set, so default to 0. int32_t processesToKeepAlive = 0; nsAutoCString keepAlivePref("dom.ipc.keepProcessesAlive."); - keepAlivePref.Append(NS_ConvertUTF16toUTF8(mRemoteType)); + + if (StringBeginsWith(mRemoteType, + NS_LITERAL_STRING(FISSION_WEB_REMOTE_TYPE)) && + xpc::IsInAutomation()) { + keepAlivePref.Append(FISSION_WEB_REMOTE_TYPE); + keepAlivePref.AppendLiteral(".perOrigin"); + } else { + keepAlivePref.Append(NS_ConvertUTF16toUTF8(mRemoteType)); + } if (NS_FAILED( Preferences::GetInt(keepAlivePref.get(), &processesToKeepAlive))) { return false; } int32_t numberOfAliveProcesses = contentParents->Length(); return numberOfAliveProcesses <= processesToKeepAlive; @@ -4943,20 +4952,16 @@ mozilla::ipc::IPCResult ContentParent::R // We always expect to open a new window here. If we don't, it's an error. if (!cwi.windowOpened() || NS_FAILED(rv)) { if (newTab) { newTab->Destroy(); } } }); - // Content has requested that we open this new content window, so - // we must have an opener. - newTab->SetHasContentOpener(true); - BrowserParent::AutoUseNewTab aunt(newTab, &cwi.urlToLoad()); const uint64_t nextRemoteTabId = ++sNextRemoteTabId; sNextBrowserParents.Put(nextRemoteTabId, newTab); const nsCOMPtr<nsIURI> uriToLoad = DeserializeURI(aURIToLoad); nsCOMPtr<nsIRemoteTab> newRemoteTab; int32_t openLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW;
--- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -47,16 +47,17 @@ #define CHILD_PROCESS_SHUTDOWN_MESSAGE \ NS_LITERAL_STRING("child-process-shutdown") // These must match the similar ones in E10SUtils.jsm and ProcInfo.h. // Process names as reported by about:memory are defined in // ContentChild:RecvRemoteType. Add your value there too or it will be called // "Web Content". #define DEFAULT_REMOTE_TYPE "web" +#define FISSION_WEB_REMOTE_TYPE "webIsolated" #define FILE_REMOTE_TYPE "file" #define EXTENSION_REMOTE_TYPE "extension" #define PRIVILEGEDABOUT_REMOTE_TYPE "privilegedabout" #define PRIVILEGEDMOZILLA_REMOTE_TYPE "privilegedmozilla" #define WITH_COOP_COEP_REMOTE_TYPE_PREFIX "webCOOP+COEP=" // This must start with the DEFAULT_REMOTE_TYPE above. #define LARGE_ALLOCATION_REMOTE_TYPE "webLargeAllocation"
--- a/dom/l10n/tests/mochitest/chrome.ini +++ b/dom/l10n/tests/mochitest/chrome.ini @@ -6,16 +6,17 @@ [l10n_overlays/test_same_id.html] [l10n_overlays/test_same_id_args.html] [l10n_mutations/test_append_content_post_dcl.html] [l10n_mutations/test_append_content_pre_dcl.html] [l10n_mutations/test_append_fragment_post_dcl.html] [l10n_mutations/test_set_attributes.html] [l10n_mutations/test_pause_observing.html] +[l10n_mutations/test_template.html] [dom_localization/test_attr_sanitized.html] [dom_localization/test_getAttributes.html] [dom_localization/test_setAttributes.html] [dom_localization/test_translateElements.html] [dom_localization/test_translateFragment.html] [dom_localization/test_connectRoot.html] [dom_localization/test_connectRoot_webcomponent.html]
new file mode 100644 --- /dev/null +++ b/dom/l10n/tests/mochitest/l10n_mutations/test_template.html @@ -0,0 +1,37 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test L10n Mutations in Template elements</title> + <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> + <link rel="localization" href="crashreporter/aboutcrashes.ftl"/> + <script type="application/javascript"> + "use strict"; + SimpleTest.waitForExplicitFinish(); + + document.addEventListener("DOMContentLoaded", async () => { + await document.l10n.ready; + let template = document.getElementById("template"); + let clone = document.importNode(template.content, true); + let span = clone.querySelector("span"); + is(span.textContent.length, 0, + "Element has not been translated while in template"); + document.body.appendChild(clone); + + let verifyL10n = () => { + if (span.textContent.length > 0) { + window.removeEventListener("MozAfterPaint", verifyL10n); + SimpleTest.finish(); + } + }; + window.addEventListener("MozAfterPaint", verifyL10n); + }); + </script> +</head> +<body> + <template id="template"> + <span data-l10n-id="crash-reports-title"></span> + </template> +</body> +</html>
--- a/dom/media/test/file_autoplay_policy_activation_frame.html +++ b/dom/media/test/file_autoplay_policy_activation_frame.html @@ -13,16 +13,17 @@ </style> </head> <body> <script> window.addEventListener("message", (event) => { if (event.data == "click") { SpecialPowers.wrap(document).notifyUserGestureActivation(); + event.source.postMessage("activated", "*"); } else if (event.data == "play-audible") { playAndPostResult(false, event.source); } else if (event.data == "play-muted") { playAndPostResult(true, event.source); } }); let w = window.opener || window.parent; w.postMessage("ready", "*");
--- a/dom/media/test/file_autoplay_policy_activation_window.html +++ b/dom/media/test/file_autoplay_policy_activation_window.html @@ -12,55 +12,69 @@ <script src="/tests/SimpleTest/EventUtils.js"></script> <script type="text/javascript" src="manifest.js"></script> <script type="text/javascript" src="AutoplayTestUtils.js"></script> </head> <body> <pre id="test"> <script> - function testAutoplayInWindow(test_case, parent_window) { - log("testAutoplayInWindow: " + test_case.name); - playAndPostResult(test_case.muted, parent_window); - } - - async function testAutoplayInChildFrame(test_case, parent_window) { - log("testAutoplayInChildFrame: " + test_case.name); - // Create a child iframe... - var frame = document.createElement("iframe"); - var origin = test_case.same_origin_child + async function createChildFrame(testInfo) { + let frame = document.createElement("iframe"); + let origin = testInfo.same_origin_child ? "http://mochi.test:8888" : "http://example.org"; frame.src = origin + "/tests/dom/media/test/file_autoplay_policy_activation_frame.html"; // Wait for it to load... document.body.appendChild(frame); is((await nextWindowMessage()).data, "ready", "Expected a 'ready' message"); - // Click the iframe to activate if appropriate. - if (test_case.activated_child) { - frame.contentWindow.postMessage("click", "*"); + return frame; + } + + async function activateDocument(testInfo) { + // Click the window to activate if appropriate. + if (testInfo.activated_from == "parent") { + info(`activate parent's document`); + SpecialPowers.wrap(document).notifyUserGestureActivation(); + } else if (testInfo.activated_from == "child") { + info(`activate child's document`); + testInfo.childFrame.contentWindow.postMessage("click", "*"); + is((await nextWindowMessage()).data, "activated", "has activated child frame."); } + } + + function testAutoplayInWindow(testInfo) { + info(`start autoplay from parent frame`); + playAndPostResult(testInfo.muted, testInfo.parentWindow); + } + + async function testAutoplayInChildFrame(testInfo) { + info("start autoplay from " + (testInfo.same_origin_child ? "same" : "cross") + " origin child frame"); // Ask the child iframe to try to play video. - let play_message = test_case.muted ? "play-muted" : "play-audible"; - frame.contentWindow.postMessage(play_message, "*"); + let play_message = testInfo.muted ? "play-muted" : "play-audible"; + testInfo.childFrame.contentWindow.postMessage(play_message, "*"); // Wait for the iframe to tell us whether it could play video. let result = await nextWindowMessage(); // Report whether the iframe could play to the parent. - parent_window.postMessage(result.data, "*"); + testInfo.parentWindow.postMessage(result.data, "*"); } nextWindowMessage().then( - (event) => { - let test_case = event.data; - // Click the window to activate if appropriate. - if (test_case.activated_parent) { - SpecialPowers.wrap(document).notifyUserGestureActivation(); - } - let parent_window = event.source; - if (test_case.same_origin_child === undefined) { - testAutoplayInWindow(test_case, parent_window); - } else { - testAutoplayInChildFrame(test_case, parent_window); + async (event) => { + let testInfo = event.data; + testInfo.parentWindow = event.source; + testInfo.childFrame = await createChildFrame(testInfo); + + await activateDocument(testInfo); + switch (testInfo.play_from) { + case "parent": + testAutoplayInWindow(testInfo); + break; + case "child": + testAutoplayInChildFrame(testInfo); + break; + default: + ok(false, "Incorrect 'play_from' value!") } }); - </script> </pre> </body> </html>
--- a/dom/media/test/test_autoplay_policy_activation.html +++ b/dom/media/test/test_autoplay_policy_activation.html @@ -18,121 +18,143 @@ ["media.autoplay.enabled.user-gestures-needed", true]); SpecialPowers.pushPrefEnv({'set': gTestPrefs}, () => { runTest(); }); let test_cases = [ { - name: "inaudible playback in unactivated same-origin iframe in activated parent allowed", + name: "inaudible playback in unactivated same-origin iframe in activated parent -> allowed", muted: true, same_origin_child: true, - activated_child: false, - activated_parent: true, + activated_from: "parent", + play_from: "child", should_play: true, }, { - name: "inaudible playback in unactivated same-origin iframe in unactivated parent allowed", + name: "inaudible playback in unactivated same-origin iframe in unactivated parent -> allowed", muted: true, same_origin_child: true, - activated_child: false, - activated_parent: false, + activated_from: "none", + play_from: "child", + should_play: true, + }, + + { + name: "audible playback in unactivated same-origin iframe in activated parent -> allowed", + muted: false, + same_origin_child: true, + activated_from: "parent", + play_from: "child", should_play: true, }, { - name: "audible playback in unactivated same-origin iframe in activated parent allowed", + name: "audible playback in unactivated same-origin iframe in unactivated parent -> blocked", muted: false, same_origin_child: true, - activated_child: false, - activated_parent: true, + activated_from: "none", + play_from: "child", + should_play: false, + }, + + { + name: "inaudible playback in unactivated cross-origin iframe in activated parent -> allowed", + muted: true, + same_origin_child: false, + activated_from: "parent", + play_from: "child", should_play: true, }, { - name: "audible playback in unactivated same-origin iframe in unactivated parent blocked", - muted: false, - same_origin_child: true, - activated_child: false, - activated_parent: false, - should_play: false, + name: "inaudible playback in unactivated cross-origin iframe in unactivated parent -> allowed", + muted: true, + same_origin_child: false, + activated_from: "none", + play_from: "child", + should_play: true, }, { - name: "inaudible playback in unactivated cross-origin iframe in activated parent allowed", - muted: true, + name: "audible playback in unactivated cross-origin iframe in activated parent -> allowed", + muted: false, same_origin_child: false, - activated_child: false, - activated_parent: true, + activated_from: "parent", + play_from: "child", should_play: true, }, { - name: "inaudible playback in unactivated cross-origin iframe in unactivated parent allowed", - muted: true, - same_origin_child: false, - activated_child: false, - activated_parent: false, - should_play: true, - }, - - { - name: "audible playback in unactivated cross-origin iframe in activated parent allowed", + name: "audible playback in unactivated cross-origin iframe in unactivated parent -> blocked", muted: false, same_origin_child: false, - activated_child: false, - activated_parent: true, - should_play: true, - }, - - { - name: "audible playback in unactivated cross-origin iframe in unactivated parent blocked", - muted: false, - same_origin_child: false, - activated_child: false, - activated_parent: false, + activated_from: "none", + play_from: "child", should_play: false, }, { - name: "audible playback in activated cross-origin iframe allowed", + name: "audible playback in activated cross-origin iframe -> allowed", muted: false, same_origin_child: false, - activated_child: true, - activated_parent: false, + activated_from: "child", + play_from: "child", should_play: true, }, { - name: "audible playback in activated document allowed", + name: "audible playback in activated document -> allowed", muted: false, - activated_parent: true, + activated_from: "parent", + play_from: "parent", should_play: true, }, { - name: "audible playback in unactivated document blocked", + name: "audible playback in unactivated document -> blocked", muted: false, - activated_parent: false, + activated_from: "none", + play_from: "parent", should_play: false, }, { - name: "inaudible playback in activated document allowed", - muted: true, - activated_parent: true, + name: "audible playback in activated document (via cross-origin child) -> allowed", + muted: false, + same_origin_child: false, + activated_from: "child", + play_from: "parent", should_play: true, }, { - name: "inaudible playback in unactivated document allowed", + name: "audible playback in activated document (via same-origin child) -> allowed", + muted: false, + same_origin_child: true, + activated_from: "child", + play_from: "parent", + should_play: true, + }, + + { + name: "inaudible playback in activated document -> allowed", muted: true, - activated_parent: false, + activated_from: "parent", + play_from: "parent", + should_play: true, + }, + + { + name: "inaudible playback in unactivated document -> allowed", + muted: true, + activated_from: "none", + play_from: "parent", should_play: true, }, ]; let child_url = "file_autoplay_policy_activation_window.html"; async function runTest() {
--- a/dom/moz.build +++ b/dom/moz.build @@ -103,21 +103,16 @@ DIRS += [ 'serviceworkers', 'simpledb', 'reporting', 'localstorage', 'prio', 'l10n', ] -if CONFIG['MOZ_XBL']: - DIRS += ['xbl'] -else: - EXPORTS += ['xbl/stub/nsXBLBinding.h'] - if CONFIG['OS_ARCH'] == 'WINNT': DIRS += ['plugins/ipc/hangui'] DIRS += ['presentation'] TEST_DIRS += [ 'tests', 'imptests',
--- a/dom/prototype/moz.build +++ b/dom/prototype/moz.build @@ -15,14 +15,11 @@ SOURCES += [ 'PrototypeDocumentContentSink.cpp', ] LOCAL_INCLUDES += [ '/dom/base', '/dom/xul', ] -if CONFIG['MOZ_XBL']: - LOCAL_INCLUDES += ['/dom/xbl'] - MOCHITEST_CHROME_MANIFESTS += ['tests/chrome/chrome.ini'] FINAL_LIBRARY = 'xul'
--- a/dom/serviceworkers/ServiceWorkerPrivate.cpp +++ b/dom/serviceworkers/ServiceWorkerPrivate.cpp @@ -119,17 +119,17 @@ ServiceWorkerPrivate::~ServiceWorkerPriv MOZ_ASSERT(mSupportsArray.IsEmpty()); MOZ_ASSERT(mIdlePromiseHolder.IsEmpty()); mIdleWorkerTimer->Cancel(); } namespace { -class CheckScriptEvaluationWithCallback final : public WorkerRunnable { +class CheckScriptEvaluationWithCallback final : public WorkerDebuggeeRunnable { nsMainThreadPtrHandle<ServiceWorkerPrivate> mServiceWorkerPrivate; nsMainThreadPtrHandle<KeepAliveToken> mKeepAliveToken; // The script evaluation result must be reported even if the runnable // is cancelled. RefPtr<LifeCycleEventCallback> mScriptEvaluationCallback; #ifdef DEBUG @@ -137,17 +137,17 @@ class CheckScriptEvaluationWithCallback #endif public: CheckScriptEvaluationWithCallback( WorkerPrivate* aWorkerPrivate, ServiceWorkerPrivate* aServiceWorkerPrivate, KeepAliveToken* aKeepAliveToken, LifeCycleEventCallback* aScriptEvaluationCallback) - : WorkerRunnable(aWorkerPrivate), + : WorkerDebuggeeRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount), mServiceWorkerPrivate(new nsMainThreadPtrHolder<ServiceWorkerPrivate>( "CheckScriptEvaluationWithCallback::mServiceWorkerPrivate", aServiceWorkerPrivate)), mKeepAliveToken(new nsMainThreadPtrHolder<KeepAliveToken>( "CheckScriptEvaluationWithCallback::mKeepAliveToken", aKeepAliveToken)), mScriptEvaluationCallback(aScriptEvaluationCallback) #ifdef DEBUG
--- a/dom/svg/moz.build +++ b/dom/svg/moz.build @@ -254,13 +254,10 @@ LOCAL_INCLUDES += [ '/dom/xml', '/layout/base', '/layout/generic', '/layout/style', '/layout/svg', '/layout/xul', ] -if CONFIG['MOZ_XBL']: - LOCAL_INCLUDES += ['/dom/xbl'] - if CONFIG['CC_TYPE'] in ('clang', 'gcc'): CXXFLAGS += ['-Wno-error=shadow']
--- a/dom/worklet/WorkletThread.cpp +++ b/dom/worklet/WorkletThread.cpp @@ -368,17 +368,17 @@ void WorkletThread::Terminate() { nsContentUtils::UnregisterShutdownObserver(this); RefPtr<TerminateRunnable> runnable = new TerminateRunnable(this); DispatchRunnable(runnable.forget()); } void WorkletThread::TerminateInternal() { - AssertIsOnWorkletThread(); + MOZ_ASSERT(!CycleCollectedJSContext::Get() || IsOnWorkletThread()); mExitLoop = true; nsCOMPtr<nsIRunnable> runnable = NewRunnableMethod( "WorkletThread::Shutdown", this, &WorkletThread::Shutdown); NS_DispatchToMainThread(runnable); }
deleted file mode 100644 --- a/dom/xbl/XBLChildrenElement.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* 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/. */ - -#include "mozilla/dom/XBLChildrenElement.h" - -#include "mozilla/PresShell.h" -#include "mozilla/dom/NodeListBinding.h" -#include "nsAttrValueOrString.h" -#include "nsCharSeparatedTokenizer.h" - -namespace mozilla { -namespace dom { - -XBLChildrenElement::~XBLChildrenElement() {} - -NS_IMPL_ELEMENT_CLONE(XBLChildrenElement) - -nsresult XBLChildrenElement::BeforeSetAttr(int32_t aNamespaceID, nsAtom* aName, - const nsAttrValueOrString* aValue, - bool aNotify) { - if (aNamespaceID == kNameSpaceID_None) { - if (aName == nsGkAtoms::includes) { - mIncludes.Clear(); - if (aValue) { - nsCharSeparatedTokenizer tok( - aValue->String(), '|', - nsCharSeparatedTokenizer::SEPARATOR_OPTIONAL); - while (tok.hasMoreTokens()) { - mIncludes.AppendElement(NS_Atomize(tok.nextToken())); - } - } - } - } - - return nsXMLElement::BeforeSetAttr(aNamespaceID, aName, aValue, aNotify); -} - -void XBLChildrenElement::DoRemoveDefaultContent(bool aNotify) { - // Default content is going away, need to tell layout about it first. - MOZ_ASSERT(HasChildren(), "Why bothering?"); - MOZ_ASSERT(GetParentElement()); - - // We don't want to do this from frame construction while setting up the - // binding initially. - if (aNotify) { - Element* parent = GetParentElement(); - if (Document* doc = parent->GetComposedDoc()) { - if (PresShell* presShell = doc->GetPresShell()) { - presShell->DestroyFramesForAndRestyle(parent); - } - } - } - - for (nsIContent* child = static_cast<nsINode*>(this)->GetFirstChild(); child; - child = child->GetNextSibling()) { - MOZ_ASSERT(!child->GetPrimaryFrame()); - MOZ_ASSERT(!child->IsElement() || !child->AsElement()->HasServoData()); - child->SetXBLInsertionPoint(nullptr); - } -} - -} // namespace dom -} // namespace mozilla - -using namespace mozilla::dom; - -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsAnonymousContentList, mParent) - -NS_IMPL_CYCLE_COLLECTING_ADDREF(nsAnonymousContentList) -NS_IMPL_CYCLE_COLLECTING_RELEASE(nsAnonymousContentList) - -NS_INTERFACE_TABLE_HEAD(nsAnonymousContentList) - NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY - NS_INTERFACE_TABLE(nsAnonymousContentList, nsINodeList) - NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsAnonymousContentList) -NS_INTERFACE_MAP_END - -uint32_t nsAnonymousContentList::Length() { - if (!mParent) { - return 0; - } - - uint32_t count = 0; - for (nsIContent* child = mParent->GetFirstChild(); child; - child = child->GetNextSibling()) { - if (child->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) { - XBLChildrenElement* point = static_cast<XBLChildrenElement*>(child); - if (point->HasInsertedChildren()) { - count += point->InsertedChildrenLength(); - } else { - count += point->GetChildCount(); - } - } else { - ++count; - } - } - - return count; -} - -nsIContent* nsAnonymousContentList::Item(uint32_t aIndex) { - if (!mParent) { - return nullptr; - } - - uint32_t remIndex = aIndex; - for (nsIContent* child = mParent->GetFirstChild(); child; - child = child->GetNextSibling()) { - if (child->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) { - XBLChildrenElement* point = static_cast<XBLChildrenElement*>(child); - if (point->HasInsertedChildren()) { - if (remIndex < point->InsertedChildrenLength()) { - return point->InsertedChild(remIndex); - } - remIndex -= point->InsertedChildrenLength(); - } else { - if (remIndex < point->GetChildCount()) { - return point->GetChildAt_Deprecated(remIndex); - } - remIndex -= point->GetChildCount(); - } - } else { - if (remIndex == 0) { - return child; - } - --remIndex; - } - } - - return nullptr; -} - -int32_t nsAnonymousContentList::IndexOf(nsIContent* aContent) { - NS_ASSERTION( - !aContent->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL), - "Looking for insertion point"); - - if (!mParent) { - return -1; - } - - int32_t index = 0; - for (nsIContent* child = mParent->GetFirstChild(); child; - child = child->GetNextSibling()) { - if (child->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) { - XBLChildrenElement* point = static_cast<XBLChildrenElement*>(child); - if (point->HasInsertedChildren()) { - int32_t insIndex = point->IndexOfInsertedChild(aContent); - if (insIndex != -1) { - return index + insIndex; - } - index += point->InsertedChildrenLength(); - } else { - int32_t insIndex = point->ComputeIndexOf(aContent); - if (insIndex != -1) { - return index + insIndex; - } - index += point->GetChildCount(); - } - } else { - if (child == aContent) { - return index; - } - ++index; - } - } - - return -1; -} - -JSObject* nsAnonymousContentList::WrapObject( - JSContext* cx, JS::Handle<JSObject*> aGivenProto) { - return mozilla::dom::NodeList_Binding::Wrap(cx, this, aGivenProto); -}
deleted file mode 100644 --- a/dom/xbl/XBLChildrenElement.h +++ /dev/null @@ -1,155 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* 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 nsXBLChildrenElement_h___ -#define nsXBLChildrenElement_h___ - -#include "nsINodeList.h" -#include "nsBindingManager.h" -#include "mozilla/dom/nsXMLElement.h" - -class nsAnonymousContentList; - -namespace mozilla { -namespace dom { - -class XBLChildrenElement : public nsXMLElement { - public: - explicit XBLChildrenElement( - already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo) - : nsXMLElement(std::move(aNodeInfo)) {} - - // nsISupports - NS_INLINE_DECL_REFCOUNTING_INHERITED(XBLChildrenElement, nsXMLElement) - - // nsINode interface methods - virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override; - - void AppendInsertedChild(nsIContent* aChild, bool aNotify) { - // Appending an inserted child causes the inserted - // children to be projected instead of default content. - MaybeRemoveDefaultContent(aNotify); - - mInsertedChildren.AppendElement(aChild); - aChild->SetXBLInsertionPoint(this); - } - - void InsertInsertedChildAt(nsIContent* aChild, uint32_t aIndex) { - // Inserting an inserted child causes the inserted - // children to be projected instead of default content. - MaybeRemoveDefaultContent(true); - - mInsertedChildren.InsertElementAt(aIndex, aChild); - aChild->SetXBLInsertionPoint(this); - } - - void RemoveInsertedChild(nsIContent* aChild) { - // Can't use this assertion as we cheat for dynamic insertions and - // only insert in the innermost insertion point. - // NS_ASSERTION(mInsertedChildren.Contains(aChild), - // "Removing child that's not there"); - mInsertedChildren.RemoveElement(aChild); - - // After removing the inserted child, default content - // may be projected into this insertion point. - // - // FIXME: Layout should be told about this before clearing - // mInsertedChildren, this leaves stale styles and frames in the frame tree. - MaybeSetupDefaultContent(); - } - - void ClearInsertedChildren() { - for (auto* child : mInsertedChildren) { - if (child->GetXBLInsertionPoint() == this) { - child->SetXBLInsertionPoint(nullptr); - } - } - mInsertedChildren.Clear(); - - // After clearing inserted children, default content - // will be projected into this insertion point. - // - // FIXME: Layout should be told about this before clearing - // mInsertedChildren, this leaves stale styles and frames in the frame tree. - MaybeSetupDefaultContent(); - } - - void MaybeSetupDefaultContent() { - if (!HasInsertedChildren()) { - for (nsIContent* child = static_cast<nsINode*>(this)->GetFirstChild(); - child; child = child->GetNextSibling()) { - child->SetXBLInsertionPoint(this); - } - } - } - - void MaybeRemoveDefaultContent(bool aNotify) { - if (!HasInsertedChildren() && HasChildren()) { - DoRemoveDefaultContent(aNotify); - } - } - - uint32_t InsertedChildrenLength() { return mInsertedChildren.Length(); } - - bool HasInsertedChildren() { return !mInsertedChildren.IsEmpty(); } - - int32_t IndexOfInsertedChild(nsIContent* aChild) { - return mInsertedChildren.IndexOf(aChild); - } - - bool Includes(nsIContent* aChild) { - NS_ASSERTION(!mIncludes.IsEmpty(), - "Shouldn't check for includes on default insertion point"); - return mIncludes.Contains(aChild->NodeInfo()->NameAtom()); - } - - bool IsDefaultInsertion() { return mIncludes.IsEmpty(); } - - nsIContent* InsertedChild(uint32_t aIndex) { - return mInsertedChildren[aIndex]; - } - - protected: - ~XBLChildrenElement(); - virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsAtom* aName, - const nsAttrValueOrString* aValue, - bool aNotify) override; - - void DoRemoveDefaultContent(bool aNotify); - - private: - nsTArray<nsIContent*> mInsertedChildren; // WEAK - nsTArray<RefPtr<nsAtom> > mIncludes; -}; - -} // namespace dom -} // namespace mozilla - -class nsAnonymousContentList final : public nsINodeList { - public: - explicit nsAnonymousContentList(nsIContent* aParent) : mParent(aParent) {} - - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsAnonymousContentList) - - // nsINodeList interface - virtual int32_t IndexOf(nsIContent* aContent) override; - virtual nsINode* GetParentObject() override { return mParent; } - virtual nsIContent* Item(uint32_t aIndex) override; - uint32_t Length() override; - - virtual JSObject* WrapObject(JSContext* cx, - JS::Handle<JSObject*> aGivenProto) override; - - bool IsListFor(nsIContent* aContent) { return mParent == aContent; } - - private: - virtual ~nsAnonymousContentList() {} - - nsCOMPtr<nsIContent> mParent; -}; - -#endif // nsXBLChildrenElement_h___
deleted file mode 100644 --- a/dom/xbl/moz.build +++ /dev/null @@ -1,54 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -with Files("**"): - BUG_COMPONENT = ("Core", "XBL") - -EXPORTS += [ - 'nsBindingManager.h', - 'nsXBLBinding.h', - 'nsXBLPrototypeHandler.h', - 'nsXBLService.h', -] - -EXPORTS.mozilla.dom += [ - 'XBLChildrenElement.h', -] - -UNIFIED_SOURCES += [ - 'nsBindingManager.cpp', - 'nsXBLBinding.cpp', - 'nsXBLContentSink.cpp', - 'nsXBLDocumentInfo.cpp', - 'nsXBLEventHandler.cpp', - 'nsXBLProtoImpl.cpp', - 'nsXBLProtoImplField.cpp', - 'nsXBLProtoImplMethod.cpp', - 'nsXBLProtoImplProperty.cpp', - 'nsXBLPrototypeBinding.cpp', - 'nsXBLPrototypeHandler.cpp', - 'nsXBLSerialize.cpp', - 'nsXBLService.cpp', - 'XBLChildrenElement.cpp', -] - -LOCAL_INCLUDES += [ - '/dom/base', - '/dom/html', - '/dom/xml', - '/dom/xul', - '/layout/style', -] - -include('/ipc/chromium/chromium-config.mozbuild') - -FINAL_LIBRARY = 'xul' - -MOCHITEST_MANIFESTS += ['test/mochitest.ini'] -MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini'] - -if CONFIG['CC_TYPE'] in ('clang', 'gcc'): - CXXFLAGS += ['-Wno-error=shadow']
deleted file mode 100644 --- a/dom/xbl/nsBindingManager.cpp +++ /dev/null @@ -1,876 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* 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/. */ - -#include "nsBindingManager.h" - -#include "nsAutoPtr.h" -#include "nsCOMPtr.h" -#include "nsXBLService.h" -#include "nsIInputStream.h" -#include "nsIURI.h" -#include "nsIURL.h" -#include "nsIChannel.h" -#include "nsString.h" -#include "plstr.h" -#include "nsIContent.h" -#include "nsIContentInlines.h" -#include "mozilla/dom/Document.h" -#include "nsContentUtils.h" -#include "nsIXMLContentSink.h" -#include "nsContentCID.h" -#include "mozilla/dom/XMLDocument.h" -#include "nsIStreamListener.h" -#include "ChildIterator.h" -#include "nsITimer.h" - -#include "nsXBLBinding.h" -#include "nsXBLPrototypeBinding.h" -#include "nsXBLDocumentInfo.h" -#include "mozilla/dom/XBLChildrenElement.h" -#ifdef MOZ_XUL -# include "nsXULPrototypeCache.h" -#endif - -#include "nsIWeakReference.h" - -#include "nsWrapperCacheInlines.h" -#include "nsIXPConnect.h" -#include "nsDOMCID.h" -#include "nsIScriptGlobalObject.h" -#include "nsTHashtable.h" - -#include "nsIScriptContext.h" -#include "xpcpublic.h" -#include "js/Wrapper.h" - -#include "nsThreadUtils.h" -#include "mozilla/dom/NodeListBinding.h" -#include "mozilla/dom/ScriptSettings.h" -#include "mozilla/PresShell.h" -#include "mozilla/PresShellInlines.h" -#include "mozilla/Unused.h" - -using namespace mozilla; -using namespace mozilla::dom; - -// Implement our nsISupports methods - -NS_IMPL_CYCLE_COLLECTION_CLASS(nsBindingManager) - -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsBindingManager) - tmp->mDestroyed = true; - - if (tmp->mBoundContentSet) tmp->mBoundContentSet->Clear(); - - if (tmp->mDocumentTable) tmp->mDocumentTable->Clear(); - - if (tmp->mLoadingDocTable) tmp->mLoadingDocTable->Clear(); - - if (tmp->mWrapperTable) { - tmp->mWrapperTable->Clear(); - tmp->mWrapperTable = nullptr; - } - - NS_IMPL_CYCLE_COLLECTION_UNLINK(mAttachedStack) - - if (tmp->mProcessAttachedQueueEvent) { - tmp->mProcessAttachedQueueEvent->Revoke(); - } -NS_IMPL_CYCLE_COLLECTION_UNLINK_END - -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsBindingManager) - // The hashes keyed on nsIContent are traversed from the nsIContent itself. - if (tmp->mDocumentTable) { - for (auto iter = tmp->mDocumentTable->Iter(); !iter.Done(); iter.Next()) { - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mDocumentTable value"); - cb.NoteXPCOMChild(iter.UserData()); - } - } - if (tmp->mLoadingDocTable) { - for (auto iter = tmp->mLoadingDocTable->Iter(); !iter.Done(); iter.Next()) { - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mLoadingDocTable value"); - cb.NoteXPCOMChild(iter.UserData()); - } - } - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAttachedStack) - // No need to traverse mProcessAttachedQueueEvent, since it'll just - // fire at some point or become revoke and drop its ref to us. -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsBindingManager) - NS_INTERFACE_MAP_ENTRY(nsIMutationObserver) - NS_INTERFACE_MAP_ENTRY(nsISupports) -NS_INTERFACE_MAP_END - -NS_IMPL_CYCLE_COLLECTING_ADDREF(nsBindingManager) -NS_IMPL_CYCLE_COLLECTING_RELEASE(nsBindingManager) - -// Constructors/Destructors -nsBindingManager::nsBindingManager(Document* aDocument) - : mProcessingAttachedStack(false), - mDestroyed(false), - mAttachedStackSizeOnOutermost(0), - mDocument(aDocument) {} - -nsBindingManager::~nsBindingManager(void) { mDestroyed = true; } - -nsXBLBinding* nsBindingManager::GetBindingWithContent( - const nsIContent* aContent) { - nsXBLBinding* binding = aContent ? aContent->GetXBLBinding() : nullptr; - return binding ? binding->GetBindingWithContent() : nullptr; -} - -void nsBindingManager::AddBoundContent(nsIContent* aContent) { - if (!mBoundContentSet) { - mBoundContentSet = new nsTHashtable<nsRefPtrHashKey<nsIContent>>; - } - mBoundContentSet->PutEntry(aContent); -} - -void nsBindingManager::RemoveBoundContent(nsIContent* aContent) { - if (mBoundContentSet) { - mBoundContentSet->RemoveEntry(aContent); - } - - // The death of the bindings means the death of the JS wrapper. - SetWrappedJS(aContent, nullptr); -} - -nsIXPConnectWrappedJS* nsBindingManager::GetWrappedJS(nsIContent* aContent) { - if (!mWrapperTable) { - return nullptr; - } - - if (!aContent || !aContent->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) { - return nullptr; - } - - return mWrapperTable->GetWeak(aContent); -} - -nsresult nsBindingManager::SetWrappedJS(nsIContent* aContent, - nsIXPConnectWrappedJS* aWrappedJS) { - if (mDestroyed) { - return NS_OK; - } - - if (aWrappedJS) { - // lazily create the table, but only when adding elements - if (!mWrapperTable) { - mWrapperTable = new WrapperHashtable(); - } - aContent->SetFlags(NODE_MAY_BE_IN_BINDING_MNGR); - - NS_ASSERTION(aContent, "key must be non-null"); - if (!aContent) return NS_ERROR_INVALID_ARG; - - mWrapperTable->Put(aContent, aWrappedJS); - - return NS_OK; - } - - // no value, so remove the key from the table - if (mWrapperTable) { - mWrapperTable->Remove(aContent); - } - - return NS_OK; -} - -void nsBindingManager::RemovedFromDocumentInternal( - nsIContent* aContent, Document* aOldDocument, - DestructorHandling aDestructorHandling) { - MOZ_ASSERT(aOldDocument != nullptr, "no old document"); - - RefPtr<nsXBLBinding> binding = aContent->GetXBLBinding(); - if (binding) { - // The binding manager may have been destroyed before a runnable - // has had a chance to reach this point. If so, we bail out on calling - // BindingDetached (which may invoke a XBL destructor) and - // ChangeDocument, but we still want to clear out the binding - // and insertion parent that may hold references. - if (!mDestroyed && aDestructorHandling == eRunDtor) { - binding->PrototypeBinding()->BindingDetached(binding->GetBoundElement()); - binding->ChangeDocument(aOldDocument, nullptr); - } - - aContent->AsElement()->SetXBLBinding(nullptr, this); - } - - // Clear out insertion point and content lists. - aContent->SetXBLInsertionPoint(nullptr); -} - -nsINodeList* nsBindingManager::GetAnonymousNodesFor(nsIContent* aContent) { - nsXBLBinding* binding = GetBindingWithContent(aContent); - return binding ? binding->GetAnonymousNodeList() : nullptr; -} - -nsresult nsBindingManager::ClearBinding(Element* aElement) { - // Hold a ref to the binding so it won't die when we remove it from our table - RefPtr<nsXBLBinding> binding = aElement ? aElement->GetXBLBinding() : nullptr; - - if (!binding) { - return NS_OK; - } - - // For now we can only handle removing a binding if it's the only one - NS_ENSURE_FALSE(binding->GetBaseBinding(), NS_ERROR_FAILURE); - - // Hold strong ref in case removing the binding tries to close the - // window or something. - // XXXbz should that be ownerdoc? Wouldn't we need a ref to the - // currentdoc too? What's the one that should be passed to - // ChangeDocument? - nsCOMPtr<Document> doc = aElement->OwnerDoc(); - - // Destroy the frames here before the UnbindFromTree happens. - if (PresShell* presShell = doc->GetPresShell()) { - presShell->DestroyFramesForAndRestyle(aElement); - } - - // Finally remove the binding... - // XXXbz this doesn't remove the implementation! Should fix! Until - // then we need the explicit UnhookEventHandlers here. - binding->UnhookEventHandlers(); - binding->ChangeDocument(doc, nullptr); - aElement->SetXBLBinding(nullptr, this); - binding->MarkForDeath(); - - // ...and recreate its frames. We need to do this since the frames may have - // been removed and style may have changed due to the removal of the - // anonymous children. - // XXXbz this should be using the current doc (if any), not the owner doc. - // get the shell again, just in case it changed - PresShell* presShell = doc->GetPresShell(); - NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); - presShell->PostRecreateFramesFor(aElement); - return NS_OK; -} - -void nsBindingManager::RemoveFromAttachedQueue(nsXBLBinding* aBinding) { - // Don't remove items here as that could mess up an executing - // ProcessAttachedQueue. Instead, null the entry in the queue. - size_t index = mAttachedStack.IndexOf(aBinding); - if (index != nsBindingList::NoIndex) { - mAttachedStack[index] = nullptr; - } -} - -nsresult nsBindingManager::AddToAttachedQueue(nsXBLBinding* aBinding) { - mAttachedStack.AppendElement(aBinding); - - // If we're in the middle of processing our queue already, don't - // bother posting the event. - if (!mProcessingAttachedStack && !mProcessAttachedQueueEvent) { - PostProcessAttachedQueueEvent(); - } - - // Make sure that flushes will flush out the new items as needed. - if (PresShell* presShell = mDocument->GetPresShell()) { - presShell->SetNeedStyleFlush(); - } - - return NS_OK; -} - -void nsBindingManager::PostProcessAttachedQueueEvent() { - MOZ_ASSERT(NS_IsMainThread()); - if (!mDocument) { - return; - } - mProcessAttachedQueueEvent = - NewRunnableMethod("nsBindingManager::DoProcessAttachedQueue", this, - &nsBindingManager::DoProcessAttachedQueue); - nsresult rv = mDocument->EventTargetFor(TaskCategory::Other) - ->Dispatch(do_AddRef(mProcessAttachedQueueEvent)); - if (NS_SUCCEEDED(rv)) { - mDocument->BlockOnload(); - } -} - -// static -void nsBindingManager::PostPAQEventCallback(nsITimer* aTimer, void* aClosure) { - RefPtr<nsBindingManager> mgr = already_AddRefed<nsBindingManager>( - static_cast<nsBindingManager*>(aClosure)); - mgr->PostProcessAttachedQueueEvent(); - NS_RELEASE(aTimer); -} - -void nsBindingManager::DoProcessAttachedQueue() { - if (!mProcessingAttachedStack) { - ProcessAttachedQueue(); - - NS_ASSERTION(mAttachedStack.Length() == 0, - "Shouldn't have pending bindings!"); - - mProcessAttachedQueueEvent = nullptr; - } else { - // Someone's doing event processing from inside a constructor. - // They're evil, but we'll fight back! Just poll on them being - // done and repost the attached queue event. - // - // But don't poll in a tight loop -- otherwise we keep the Gecko - // event loop non-empty and trigger bug 1021240 on OS X. - nsresult rv = NS_ERROR_FAILURE; - nsCOMPtr<nsITimer> timer; - rv = NS_NewTimerWithFuncCallback( - getter_AddRefs(timer), PostPAQEventCallback, this, 100, - nsITimer::TYPE_ONE_SHOT, "nsBindingManager::DoProcessAttachedQueue"); - if (NS_SUCCEEDED(rv)) { - NS_ADDREF_THIS(); - // We drop our reference to the timer here, since the timer callback is - // responsible for releasing the object. - Unused << timer.forget().take(); - } - } - - // No matter what, unblock onload for the event that's fired. - if (mDocument) { - // Hold a strong reference while calling UnblockOnload since that might - // run script. - nsCOMPtr<Document> doc = mDocument; - doc->UnblockOnload(true); - } -} - -void nsBindingManager::ProcessAttachedQueueInternal(uint32_t aSkipSize) { - mProcessingAttachedStack = true; - - // Excute constructors. Do this from high index to low - while (mAttachedStack.Length() > aSkipSize) { - uint32_t lastItem = mAttachedStack.Length() - 1; - RefPtr<nsXBLBinding> binding = mAttachedStack.ElementAt(lastItem); - mAttachedStack.RemoveElementAt(lastItem); - if (binding) { - binding->ExecuteAttachedHandler(); - } - } - - // If NodeWillBeDestroyed has run we don't want to clobber - // mProcessingAttachedStack set there. - if (mDocument) { - mProcessingAttachedStack = false; - } - - NS_ASSERTION(mAttachedStack.Length() == aSkipSize, "How did we get here?"); - - mAttachedStack.Compact(); -} - -// Keep bindings and bound elements alive while executing detached handlers. -void nsBindingManager::ExecuteDetachedHandlers() { - // Walk our hashtable of bindings. - if (!mBoundContentSet) { - return; - } - - nsCOMArray<nsIContent> boundElements; - nsBindingList bindings; - - for (auto iter = mBoundContentSet->Iter(); !iter.Done(); iter.Next()) { - nsXBLBinding* binding = iter.Get()->GetKey()->GetXBLBinding(); - if (binding && bindings.AppendElement(binding)) { - if (!boundElements.AppendObject(binding->GetBoundElement())) { - bindings.RemoveLastElement(); - } - } - } - - uint32_t i, count = bindings.Length(); - for (i = 0; i < count; ++i) { - bindings[i]->ExecuteDetachedHandler(); - } -} - -nsresult nsBindingManager::PutXBLDocumentInfo( - nsXBLDocumentInfo* aDocumentInfo) { - MOZ_ASSERT(aDocumentInfo, "Must have a non-null documentinfo!"); - - if (!mDocumentTable) { - mDocumentTable = new nsRefPtrHashtable<nsURIHashKey, nsXBLDocumentInfo>(); - } - - mDocumentTable->Put(aDocumentInfo->DocumentURI(), aDocumentInfo); - - return NS_OK; -} - -void nsBindingManager::RemoveXBLDocumentInfo(nsXBLDocumentInfo* aDocumentInfo) { - if (mDocumentTable) { - mDocumentTable->Remove(aDocumentInfo->DocumentURI()); - } -} - -nsXBLDocumentInfo* nsBindingManager::GetXBLDocumentInfo(nsIURI* aURL) { - if (!mDocumentTable) return nullptr; - - return mDocumentTable->GetWeak(aURL); -} - -nsresult nsBindingManager::PutLoadingDocListener(nsIURI* aURL, - nsIStreamListener* aListener) { - MOZ_ASSERT(aListener, "Must have a non-null listener!"); - - if (!mLoadingDocTable) { - mLoadingDocTable = - new nsInterfaceHashtable<nsURIHashKey, nsIStreamListener>(); - } - mLoadingDocTable->Put(aURL, aListener); - - return NS_OK; -} - -nsIStreamListener* nsBindingManager::GetLoadingDocListener(nsIURI* aURL) { - if (!mLoadingDocTable) return nullptr; - - return mLoadingDocTable->GetWeak(aURL); -} - -void nsBindingManager::RemoveLoadingDocListener(nsIURI* aURL) { - if (mLoadingDocTable) { - mLoadingDocTable->Remove(aURL); - } -} - -// Used below to protect from recurring in QI calls through XPConnect. -struct AntiRecursionData { - nsIContent* element; - REFNSIID iid; - AntiRecursionData* next; - - AntiRecursionData(nsIContent* aElement, REFNSIID aIID, - AntiRecursionData* aNext) - : element(aElement), iid(aIID), next(aNext) {} -}; - -nsresult nsBindingManager::GetBindingImplementation(nsIContent* aContent, - REFNSIID aIID, - void** aResult) { - *aResult = nullptr; - nsXBLBinding* binding = aContent ? aContent->GetXBLBinding() : nullptr; - if (binding) { - // The binding should not be asked for nsISupports - NS_ASSERTION(!aIID.Equals(NS_GET_IID(nsISupports)), - "Asking a binding for nsISupports"); - if (binding->ImplementsInterface(aIID)) { - nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS = GetWrappedJS(aContent); - - if (wrappedJS) { - // Protect from recurring in QI calls through XPConnect. - // This can happen when a second binding is being resolved. - // At that point a wrappedJS exists, but it doesn't yet know about - // the iid we are asking for. So, without this protection, - // AggregatedQueryInterface would end up recurring back into itself - // through this code. - // - // With this protection, when we detect the recursion we return - // NS_NOINTERFACE in the inner call. The outer call will then fall - // through (see below) and build a new chained wrappedJS for the iid. - // - // We're careful to not assume that only one direct nesting can occur - // because there is a call into JS in the middle and we can't assume - // that this code won't be reached by some more complex nesting path. - // - // NOTE: We *assume* this is single threaded, so we can use a - // static linked list to do the check. - - static AntiRecursionData* list = nullptr; - - for (AntiRecursionData* p = list; p; p = p->next) { - if (p->element == aContent && p->iid.Equals(aIID)) { - *aResult = nullptr; - return NS_NOINTERFACE; - } - } - - AntiRecursionData item(aContent, aIID, list); - list = &item; - - nsresult rv = wrappedJS->AggregatedQueryInterface(aIID, aResult); - - list = item.next; - - if (*aResult) return rv; - - // No result was found, so this must be another XBL interface. - // Fall through to create a new wrapper. - } - - // We have never made a wrapper for this implementation. - // Create an XPC wrapper for the script object and hand it back. - AutoJSAPI jsapi; - jsapi.Init(); - JSContext* cx = jsapi.cx(); - - nsIXPConnect* xpConnect = nsContentUtils::XPConnect(); - - JS::Rooted<JSObject*> jsobj(cx, aContent->GetWrapper()); - NS_ENSURE_TRUE(jsobj, NS_NOINTERFACE); - - // If we're using an XBL scope, we need to use the Xray view to the bound - // content in order to view the full array of methods defined in the - // binding, some of which may not be exposed on the prototype of - // untrusted content. We don't need to consider add-on scopes here - // because they're chrome-only and no Xrays are involved. - // - // If there's no separate XBL scope, or if the reflector itself lives in - // the XBL scope, we'll end up with the global of the reflector. - JS::Rooted<JSObject*> xblScope(cx, xpc::GetXBLScopeOrGlobal(cx, jsobj)); - NS_ENSURE_TRUE(xblScope, NS_ERROR_UNEXPECTED); - JSAutoRealm ar(cx, xblScope); - bool ok = JS_WrapObject(cx, &jsobj); - NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY); - MOZ_ASSERT_IF(js::IsWrapper(jsobj), xpc::IsXrayWrapper(jsobj)); - - nsresult rv = xpConnect->WrapJSAggregatedToNative(aContent, cx, jsobj, - aIID, aResult); - if (NS_FAILED(rv)) return rv; - - // We successfully created a wrapper. We will own this wrapper for as - // long as the binding remains alive. At the time the binding is cleared - // out of the bindingManager, we will remove the wrapper from the - // bindingManager as well. - nsISupports* supp = static_cast<nsISupports*>(*aResult); - wrappedJS = do_QueryInterface(supp); - SetWrappedJS(aContent, wrappedJS); - - return rv; - } - } - - *aResult = nullptr; - return NS_NOINTERFACE; -} - -static void InsertAppendedContent(XBLChildrenElement* aPoint, - nsIContent* aFirstNewContent) { - int32_t insertionIndex; - if (nsIContent* prevSibling = aFirstNewContent->GetPreviousSibling()) { - // If we have a previous sibling, then it must already be in aPoint. Find - // it and insert after it. - insertionIndex = aPoint->IndexOfInsertedChild(prevSibling); - MOZ_ASSERT(insertionIndex != -1); - - // Our insertion index is one after our previous sibling's index. - ++insertionIndex; - } else { - // Otherwise, we append. - // TODO This is wrong for nested insertion points. In that case, we need to - // keep track of the right index to insert into. - insertionIndex = aPoint->InsertedChildrenLength(); - } - - // Do the inserting. - for (nsIContent* currentChild = aFirstNewContent; currentChild; - currentChild = currentChild->GetNextSibling()) { - aPoint->InsertInsertedChildAt(currentChild, insertionIndex++); - } -} - -void nsBindingManager::ContentAppended(nsIContent* aFirstNewContent) { - // Try to find insertion points for all the new kids. - XBLChildrenElement* point = nullptr; - nsIContent* container = aFirstNewContent->GetParent(); - nsIContent* parent = container; - - // Handle appending of default content. - if (parent && parent->IsActiveChildrenElement()) { - XBLChildrenElement* childrenEl = static_cast<XBLChildrenElement*>(parent); - if (childrenEl->HasInsertedChildren()) { - // Appending default content that isn't being used. Ignore. - return; - } - - childrenEl->MaybeSetupDefaultContent(); - parent = childrenEl->GetParent(); - } - - bool first = true; - do { - nsXBLBinding* binding = GetBindingWithContent(parent); - if (!binding) { - break; - } - - if (binding->HasFilteredInsertionPoints()) { - // There are filtered insertion points involved, handle each child - // separately. - // We could optimize this in the case when we've nested a few levels - // deep already, without hitting bindings that have filtered insertion - // points. - for (nsIContent* currentChild = aFirstNewContent; currentChild; - currentChild = currentChild->GetNextSibling()) { - HandleChildInsertion(container, currentChild, true); - } - - return; - } - - point = binding->GetDefaultInsertionPoint(); - if (!point) { - break; - } - - // Even though we're in ContentAppended, nested insertion points force us - // to deal with this append as an insertion except in the outermost - // binding. - if (first) { - first = false; - for (nsIContent* child = aFirstNewContent; child; - child = child->GetNextSibling()) { - point->AppendInsertedChild(child, true); - } - } else { - InsertAppendedContent(point, aFirstNewContent); - } - - nsIContent* newParent = point->GetParent(); - if (newParent == parent) { - break; - } - parent = newParent; - } while (parent); -} - -void nsBindingManager::ContentInserted(nsIContent* aChild) { - HandleChildInsertion(aChild->GetParent(), aChild, false); -} - -void nsBindingManager::ContentRemoved(nsIContent* aChild, - nsIContent* aPreviousSibling) { - aChild->SetXBLInsertionPoint(nullptr); - - XBLChildrenElement* point = nullptr; - nsIContent* parent = aChild->GetParent(); - - // Handle appending of default content. - if (parent && parent->IsActiveChildrenElement()) { - XBLChildrenElement* childrenEl = static_cast<XBLChildrenElement*>(parent); - if (childrenEl->HasInsertedChildren()) { - // Removing default content that isn't being used. Ignore. - return; - } - - parent = childrenEl->GetParent(); - } - - do { - nsXBLBinding* binding = GetBindingWithContent(parent); - if (!binding) { - // If aChild is XBL content, it might have <xbl:children> elements - // somewhere under it. We need to inform those elements that they're no - // longer in the tree so they can tell their distributed children that - // they're no longer distributed under them. - // XXX This is wrong. We need to do far more work to update the parent - // binding's list of insertion points and to get the new insertion parent - // for the newly-distributed children correct. - if (aChild->GetBindingParent()) { - ClearInsertionPointsRecursively(aChild); - } - return; - } - - point = binding->FindInsertionPointFor(aChild); - if (!point) { - break; - } - - point->RemoveInsertedChild(aChild); - - nsIContent* newParent = point->GetParent(); - if (newParent == parent) { - break; - } - parent = newParent; - } while (parent); -} - -void nsBindingManager::ClearInsertionPointsRecursively(nsIContent* aContent) { - if (aContent->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) { - static_cast<XBLChildrenElement*>(aContent)->ClearInsertedChildren(); - } - - for (nsIContent* child = aContent->GetFirstChild(); child; - child = child->GetNextSibling()) { - ClearInsertionPointsRecursively(child); - } -} - -void nsBindingManager::DropDocumentReference() { - mDestroyed = true; - - // Make sure to not run any more XBL constructors - mProcessingAttachedStack = true; - if (mProcessAttachedQueueEvent) { - mProcessAttachedQueueEvent->Revoke(); - } - - if (mBoundContentSet) { - mBoundContentSet->Clear(); - } - - mDocument = nullptr; -} - -void nsBindingManager::Traverse(nsIContent* aContent, - nsCycleCollectionTraversalCallback& cb) { - if (!aContent->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) || - !aContent->IsElement()) { - // Don't traverse if content is not in this binding manager. - // We also don't traverse non-elements because there should not - // be bindings (checking the flag alone is not sufficient because - // the flag is also set on children of insertion points that may be - // non-elements). - return; - } - - if (mBoundContentSet && mBoundContentSet->Contains(aContent)) { - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME( - cb, "[via binding manager] mBoundContentSet entry"); - cb.NoteXPCOMChild(aContent); - } - - nsIXPConnectWrappedJS* value = GetWrappedJS(aContent); - if (value) { - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME( - cb, "[via binding manager] mWrapperTable key"); - cb.NoteXPCOMChild(aContent); - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME( - cb, "[via binding manager] mWrapperTable value"); - cb.NoteXPCOMChild(value); - } -} - -void nsBindingManager::HandleChildInsertion(nsIContent* aContainer, - nsIContent* aChild, bool aAppend) { - MOZ_ASSERT(aChild, "Must have child"); - - XBLChildrenElement* point = nullptr; - nsIContent* parent = aContainer; - - // Handle insertion of default content. - if (parent && parent->IsActiveChildrenElement()) { - XBLChildrenElement* childrenEl = static_cast<XBLChildrenElement*>(parent); - if (childrenEl->HasInsertedChildren()) { - // Inserting default content that isn't being used. Ignore. - return; - } - - childrenEl->MaybeSetupDefaultContent(); - parent = childrenEl->GetParent(); - } - - while (parent) { - nsXBLBinding* binding = GetBindingWithContent(parent); - if (!binding) { - break; - } - - point = binding->FindInsertionPointFor(aChild); - if (!point) { - break; - } - - // Insert the child into the proper insertion point. - // TODO If there were multiple insertion points, this approximation can be - // wrong. We need to re-run the distribution algorithm. In the meantime, - // this should work well enough. - uint32_t index = aAppend ? point->InsertedChildrenLength() : 0; - for (nsIContent* currentSibling = aChild->GetPreviousSibling(); - currentSibling; - currentSibling = currentSibling->GetPreviousSibling()) { - // If we find one of our previous siblings in the insertion point, the - // index following it is the correct insertion point. Otherwise, we guess - // based on whether we're appending or inserting. - int32_t pointIndex = point->IndexOfInsertedChild(currentSibling); - if (pointIndex != -1) { - index = pointIndex + 1; - break; - } - } - - point->InsertInsertedChildAt(aChild, index); - - nsIContent* newParent = point->GetParent(); - if (newParent == parent) { - break; - } - - parent = newParent; - } -} - -nsIContent* nsBindingManager::FindNestedSingleInsertionPoint( - nsIContent* aContainer, bool* aMulti) { - *aMulti = false; - - nsIContent* parent = aContainer; - if (aContainer->IsActiveChildrenElement()) { - if (static_cast<XBLChildrenElement*>(aContainer)->HasInsertedChildren()) { - return nullptr; - } - parent = aContainer->GetParent(); - } - - while (parent) { - nsXBLBinding* binding = GetBindingWithContent(parent); - if (!binding) { - break; - } - - if (binding->HasFilteredInsertionPoints()) { - *aMulti = true; - return nullptr; - } - - XBLChildrenElement* point = binding->GetDefaultInsertionPoint(); - if (!point) { - return nullptr; - } - - nsIContent* newParent = point->GetParent(); - if (newParent == parent) { - break; - } - parent = newParent; - } - - return parent; -} - -size_t nsBindingManager::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const { - size_t n = aMallocSizeOf(this); - -#define SHALLOW_SIZE_INCLUDING(field_) \ - n += field_ ? field_->ShallowSizeOfIncludingThis(aMallocSizeOf) : 0; - SHALLOW_SIZE_INCLUDING(mBoundContentSet); - SHALLOW_SIZE_INCLUDING(mWrapperTable); - SHALLOW_SIZE_INCLUDING(mLoadingDocTable); -#undef SHALLOW_SIZE_INCLUDING - n += mAttachedStack.ShallowSizeOfExcludingThis(aMallocSizeOf); - - if (mDocumentTable) { - n += mDocumentTable->ShallowSizeOfIncludingThis(aMallocSizeOf); -#ifdef MOZ_XUL - nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance(); -#endif - for (auto iter = mDocumentTable->Iter(); !iter.Done(); iter.Next()) { - nsXBLDocumentInfo* docInfo = iter.UserData(); -#ifdef MOZ_XUL - nsXBLDocumentInfo* cachedInfo = cache->GetXBLDocumentInfo(iter.Key()); - if (cachedInfo == docInfo) { - // If this binding has been cached, skip it since it can be - // reused by other documents. - continue; - } -#endif - n += docInfo->SizeOfIncludingThis(aMallocSizeOf); - } - } - - return n; -}
deleted file mode 100644 --- a/dom/xbl/nsBindingManager.h +++ /dev/null @@ -1,204 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* 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 nsBindingManager_h_ -#define nsBindingManager_h_ - -#include "nsAutoPtr.h" -#include "nsIContent.h" -#include "nsStubMutationObserver.h" -#include "nsHashKeys.h" -#include "nsInterfaceHashtable.h" -#include "nsRefPtrHashtable.h" -#include "nsURIHashKey.h" -#include "nsCycleCollectionParticipant.h" -#include "nsXBLBinding.h" -#include "nsTArray.h" -#include "nsThreadUtils.h" -#include "mozilla/MediaFeatureChange.h" -#include "mozilla/MemoryReporting.h" -#include "mozilla/EventStates.h" - -struct ElementDependentRuleProcessorData; -class nsIXPConnectWrappedJS; -class nsAtom; -class nsIURI; -class nsXBLDocumentInfo; -class nsIStreamListener; -class nsXBLBinding; -typedef nsTArray<RefPtr<nsXBLBinding> > nsBindingList; -class nsIPrincipal; -class nsITimer; - -class nsBindingManager final : public nsStubMutationObserver { - ~nsBindingManager(); - - public: - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - - NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED - NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED - NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED - - explicit nsBindingManager(mozilla::dom::Document* aDocument); - - nsXBLBinding* GetBindingWithContent(const nsIContent* aContent); - - void AddBoundContent(nsIContent* aContent); - void RemoveBoundContent(nsIContent* aContent); - - /** - * Notify the binding manager that an element - * has been removed from its document, - * so that it can update any bindings or - * nsIAnonymousContentCreator-created anonymous - * content that may depend on the document. - * @param aContent the element that's being moved - * @param aOldDocument the old document in which the - * content resided. - * @param aDestructorHandling whether or not to run the possible XBL - * destructor. - */ - - enum DestructorHandling { eRunDtor, eDoNotRunDtor }; - void RemovedFromDocument(nsIContent* aContent, - mozilla::dom::Document* aOldDocument, - DestructorHandling aDestructorHandling) { - if (aContent->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) { - RemovedFromDocumentInternal(aContent, aOldDocument, aDestructorHandling); - } - } - void RemovedFromDocumentInternal(nsIContent* aContent, - mozilla::dom::Document* aOldDocument, - DestructorHandling aDestructorHandling); - - /** - * Return the nodelist of "anonymous" kids for this node. This might - * actually include some of the nodes actual DOM kids, if there are - * <children> tags directly as kids of <content>. This will only end up - * returning a non-null list for nodes which have a binding attached. - */ - nsINodeList* GetAnonymousNodesFor(nsIContent* aContent); - - nsresult ClearBinding(mozilla::dom::Element* aElement); - - nsresult AddToAttachedQueue(nsXBLBinding* aBinding); - void RemoveFromAttachedQueue(nsXBLBinding* aBinding); - void ProcessAttachedQueue(uint32_t aSkipSize = 0) { - if (mProcessingAttachedStack || mAttachedStack.Length() <= aSkipSize) { - return; - } - - ProcessAttachedQueueInternal(aSkipSize); - } - - private: - void ProcessAttachedQueueInternal(uint32_t aSkipSize); - - public: - void ExecuteDetachedHandlers(); - - nsresult PutXBLDocumentInfo(nsXBLDocumentInfo* aDocumentInfo); - nsXBLDocumentInfo* GetXBLDocumentInfo(nsIURI* aURI); - void RemoveXBLDocumentInfo(nsXBLDocumentInfo* aDocumentInfo); - - nsresult PutLoadingDocListener(nsIURI* aURL, nsIStreamListener* aListener); - nsIStreamListener* GetLoadingDocListener(nsIURI* aURL); - void RemoveLoadingDocListener(nsIURI* aURL); - - nsresult GetBindingImplementation(nsIContent* aContent, REFNSIID aIID, - void** aResult); - - void Traverse(nsIContent* aContent, nsCycleCollectionTraversalCallback& cb); - - NS_DECL_CYCLE_COLLECTION_CLASS(nsBindingManager) - - // Notify the binding manager when an outermost update begins and - // ends. The end method can execute script. - void BeginOutermostUpdate() { - mAttachedStackSizeOnOutermost = mAttachedStack.Length(); - } - - void EndOutermostUpdate() { - if (!mProcessingAttachedStack) { - ProcessAttachedQueue(mAttachedStackSizeOnOutermost); - mAttachedStackSizeOnOutermost = 0; - } - } - - // When removing an insertion point or a parent of one, clear the insertion - // points and their insertion parents. - void ClearInsertionPointsRecursively(nsIContent* aContent); - - // Called when the document is going away - void DropDocumentReference(); - - nsIContent* FindNestedSingleInsertionPoint(nsIContent* aContainer, - bool* aMulti); - - size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; - - protected: - nsIXPConnectWrappedJS* GetWrappedJS(nsIContent* aContent); - nsresult SetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS* aResult); - - // Called by ContentAppended and ContentInserted to handle a single child - // insertion. aChild must not be null. aContainer may be null. - // aAppend is true if this child is being appended, not inserted. - void HandleChildInsertion(nsIContent* aContainer, nsIContent* aChild, - bool aAppend); - - // Same as ProcessAttachedQueue, but also nulls out - // mProcessAttachedQueueEvent - void DoProcessAttachedQueue(); - - // Post an event to process the attached queue. - void PostProcessAttachedQueueEvent(); - - // Call PostProcessAttachedQueueEvent() on a timer. - static void PostPAQEventCallback(nsITimer* aTimer, void* aClosure); - - // MEMBER VARIABLES - // A set of nsIContent that currently have a binding installed. - nsAutoPtr<nsTHashtable<nsRefPtrHashKey<nsIContent> > > mBoundContentSet; - - // A mapping from nsIContent* to nsIXPWrappedJS* (an XPConnect - // wrapper for JS objects). For XBL bindings that implement XPIDL - // interfaces, and that get referred to from C++, this table caches - // the XPConnect wrapper for the binding. By caching it, I control - // its lifetime, and I prevent a re-wrap of the same script object - // (in the case where multiple bindings in an XBL inheritance chain - // both implement an XPIDL interface). - typedef nsInterfaceHashtable<nsISupportsHashKey, nsIXPConnectWrappedJS> - WrapperHashtable; - nsAutoPtr<WrapperHashtable> mWrapperTable; - - // A mapping from a URL (a string) to nsXBLDocumentInfo*. This table - // is the cache of all binding documents that have been loaded by a - // given bound document. - nsAutoPtr<nsRefPtrHashtable<nsURIHashKey, nsXBLDocumentInfo> > mDocumentTable; - - // A mapping from a URL (a string) to a nsIStreamListener. This - // table is the currently loading binding docs. If they're in this - // table, they have not yet finished loading. - nsAutoPtr<nsInterfaceHashtable<nsURIHashKey, nsIStreamListener> > - mLoadingDocTable; - - // A queue of binding attached event handlers that are awaiting execution. - nsBindingList mAttachedStack; - bool mProcessingAttachedStack; - bool mDestroyed; - uint32_t mAttachedStackSizeOnOutermost; - - // Our posted event to process the attached queue, if any - friend class nsRunnableMethod<nsBindingManager>; - RefPtr<nsRunnableMethod<nsBindingManager> > mProcessAttachedQueueEvent; - - // Our document. This is a weak ref; the document owns us - mozilla::dom::Document* mDocument; -}; - -#endif
deleted file mode 100644 --- a/dom/xbl/nsXBLBinding.cpp +++ /dev/null @@ -1,1028 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* 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/. */ - -#include "nsCOMPtr.h" -#include "nsAtom.h" -#include "nsXBLDocumentInfo.h" -#include "nsIInputStream.h" -#include "nsNameSpaceManager.h" -#include "nsIURI.h" -#include "nsIURL.h" -#include "nsIChannel.h" -#include "nsString.h" -#include "nsReadableUtils.h" -#include "plstr.h" -#include "nsIContent.h" -#include "mozilla/dom/BindContext.h" -#include "mozilla/dom/Document.h" -#include "nsContentUtils.h" -#include "ChildIterator.h" -#include "nsIXMLContentSink.h" -#include "nsContentCID.h" -#include "mozilla/dom/XMLDocument.h" -#include "jsapi.h" -#include "nsXBLService.h" -#include "nsIXPConnect.h" -#include "nsIScriptContext.h" -#include "nsCRT.h" - -// Event listeners -#include "mozilla/EventListenerManager.h" -#include "nsIDOMEventListener.h" -#include "nsAttrName.h" - -#include "nsGkAtoms.h" - -#include "nsXBLPrototypeHandler.h" - -#include "nsXBLPrototypeBinding.h" -#include "nsXBLBinding.h" -#include "nsIPrincipal.h" -#include "nsIScriptSecurityManager.h" -#include "mozilla/dom/XBLChildrenElement.h" - -#include "nsJSUtils.h" - -#include "mozilla/DeferredFinalize.h" -#include "mozilla/dom/Element.h" -#include "mozilla/dom/ScriptSettings.h" - -using namespace mozilla; -using namespace mozilla::dom; - -// Helper classes - -/***********************************************************************/ -// -// The JS class for XBLBinding -// -static void XBLFinalize(JSFreeOp* fop, JSObject* obj) { - nsXBLDocumentInfo* docInfo = - static_cast<nsXBLDocumentInfo*>(::JS_GetPrivate(obj)); - DeferredFinalize(docInfo); -} - -static bool XBLEnumerate(JSContext* cx, JS::Handle<JSObject*> obj) { - nsXBLPrototypeBinding* protoBinding = static_cast<nsXBLPrototypeBinding*>( - ::JS_GetReservedSlot(obj, 0).toPrivate()); - MOZ_ASSERT(protoBinding); - - return protoBinding->ResolveAllFields(cx, obj); -} - -static const JSClassOps gPrototypeJSClassOps = { - nullptr, nullptr, XBLEnumerate, nullptr, nullptr, nullptr, - XBLFinalize, nullptr, nullptr, nullptr, nullptr}; - -static const JSClass gPrototypeJSClass = { - "XBL prototype JSClass", - JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS | - JSCLASS_FOREGROUND_FINALIZE | - // Our one reserved slot holds the relevant nsXBLPrototypeBinding - JSCLASS_HAS_RESERVED_SLOTS(1), - &gPrototypeJSClassOps}; - -// Implementation ////////////////////////////////////////////////////////////// - -// Constructors/Destructors -nsXBLBinding::nsXBLBinding(nsXBLPrototypeBinding* aBinding) - : mMarkedForDeath(false), - mPrototypeBinding(aBinding), - mBoundElement(nullptr) { - NS_ASSERTION(mPrototypeBinding, "Must have a prototype binding!"); - // Grab a ref to the document info so the prototype binding won't die - NS_ADDREF(mPrototypeBinding->XBLDocumentInfo()); -} - -nsXBLBinding::~nsXBLBinding() { - if (mContent) { - nsXBLBinding::UnbindAnonymousContent(mContent->OwnerDoc(), mContent); - } - nsXBLDocumentInfo* info = mPrototypeBinding->XBLDocumentInfo(); - NS_RELEASE(info); -} - -NS_IMPL_CYCLE_COLLECTION_CLASS(nsXBLBinding) - -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXBLBinding) - // XXX Probably can't unlink mPrototypeBinding->XBLDocumentInfo(), because - // mPrototypeBinding is weak. - if (tmp->mContent) { - nsXBLBinding::UnbindAnonymousContent(tmp->mContent->OwnerDoc(), - tmp->mContent); - } - NS_IMPL_CYCLE_COLLECTION_UNLINK(mContent) - NS_IMPL_CYCLE_COLLECTION_UNLINK(mNextBinding) - NS_IMPL_CYCLE_COLLECTION_UNLINK(mDefaultInsertionPoint) - NS_IMPL_CYCLE_COLLECTION_UNLINK(mInsertionPoints) - NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnonymousContentList) -NS_IMPL_CYCLE_COLLECTION_UNLINK_END -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXBLBinding) - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, - "mPrototypeBinding->XBLDocumentInfo()"); - cb.NoteXPCOMChild(tmp->mPrototypeBinding->XBLDocumentInfo()); - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContent) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNextBinding) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDefaultInsertionPoint) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInsertionPoints) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnonymousContentList) -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END -NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsXBLBinding, AddRef) -NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsXBLBinding, Release) - -void nsXBLBinding::SetBaseBinding(nsXBLBinding* aBinding) { - if (mNextBinding) { - NS_ERROR("Base XBL binding is already defined!"); - return; - } - - mNextBinding = aBinding; // Comptr handles rel/add -} - -nsXBLBinding* nsXBLBinding::GetBindingWithContent() { - if (mContent) { - return this; - } - - return mNextBinding ? mNextBinding->GetBindingWithContent() : nullptr; -} - -void nsXBLBinding::BindAnonymousContent(nsIContent* aAnonParent, - nsIContent* aElement) { - // We need to ensure two things. - // (1) The anonymous content should be fooled into thinking it's in the bound - // element's document, assuming that the bound element is in a document - // Note that we don't change the current doc of aAnonParent here, since that - // quite simply does not matter. aAnonParent is just a way of keeping refs - // to all its kids, which are anonymous content from the point of view of - // aElement. - // (2) The children's parent back pointer should not be to this synthetic root - // but should instead point to the enclosing parent element. - Element* element = aElement->AsElement(); - - nsAutoScriptBlocker scriptBlocker; - BindContext context(*this, *element); - for (nsIContent* child = aAnonParent->GetFirstChild(); child; - child = child->GetNextSibling()) { - child->UnbindFromTree(); - child->SetFlags(NODE_IS_ANONYMOUS_ROOT); - nsresult rv = child->BindToTree(context, *element); - if (NS_FAILED(rv)) { - // Oh, well... Just give up. - // XXXbz This really shouldn't be a void method! - child->UnbindFromTree(); - return; - } - } -} - -void nsXBLBinding::UnbindAnonymousContent(Document* aDocument, - nsIContent* aAnonParent, - bool aNullParent) { - nsAutoScriptBlocker scriptBlocker; - // Hold a strong ref while doing this, just in case. - nsCOMPtr<nsIContent> anonParent = aAnonParent; - for (nsIContent* child = aAnonParent->GetFirstChild(); child; - child = child->GetNextSibling()) { - child->UnbindFromTree(aNullParent); - } -} - -void nsXBLBinding::SetBoundElement(Element* aElement) { - mBoundElement = aElement; - if (mNextBinding) mNextBinding->SetBoundElement(aElement); -} - -void nsXBLBinding::GenerateAnonymousContent() { - NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(), - "Someone forgot a script blocker"); - - // Fetch the content element for this binding. - Element* content = mPrototypeBinding->GetImmediateChild(nsGkAtoms::content); - - if (!content) { - // We have no anonymous content. - if (mNextBinding) mNextBinding->GenerateAnonymousContent(); - - return; - } - - // Find out if we're really building kids or if we're just - // using the attribute-setting shorthand hack. - uint32_t contentCount = content->GetChildCount(); - - // Plan to build the content by default. - bool hasContent = (contentCount > 0); - if (hasContent) { - Document* doc = mBoundElement->OwnerDoc(); - - nsCOMPtr<nsINode> clonedNode = - content->Clone(true, doc->NodeInfoManager(), nullptr, IgnoreErrors()); - // FIXME: Bug 1399558, Why is this code OK assuming that nsINode::Clone - // never fails? - mContent = clonedNode->AsElement(); - - // Search for <xbl:children> elements in the XBL content. In the presence - // of multiple default insertion points, we use the last one in document - // order. - for (nsIContent* child = mContent; child; - child = child->GetNextNode(mContent)) { - if (child->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) { - XBLChildrenElement* point = static_cast<XBLChildrenElement*>(child); - if (point->IsDefaultInsertion()) { - mDefaultInsertionPoint = point; - } else { - mInsertionPoints.AppendElement(point); - } - } - } - - // Do this after looking for <children> as this messes up the parent - // pointer which would make the GetNextNode call above fail - BindAnonymousContent(mContent, mBoundElement); - - // Insert explicit children into insertion points - if (mDefaultInsertionPoint && mInsertionPoints.IsEmpty()) { - ExplicitChildIterator iter(mBoundElement); - for (nsIContent* child = iter.GetNextChild(); child; - child = iter.GetNextChild()) { - // Pass aNotify = false because we're just setting up the whole thing. - // Furthermore we do it from frame construction, so passing true here - // would reenter into it which is... not great. - mDefaultInsertionPoint->AppendInsertedChild(child, false); - } - } else { - // It is odd to come into this code if mInsertionPoints is not empty, but - // we need to make sure to do the compatibility hack below if the bound - // node has any non <xul:template> or <xul:observes> children. - ExplicitChildIterator iter(mBoundElement); - for (nsIContent* child = iter.GetNextChild(); child; - child = iter.GetNextChild()) { - XBLChildrenElement* point = FindInsertionPointForInternal(child); - if (point) { - // Pass aNotify = false because we're just setting up the whole thing. - // (see the similar call above for more details). - point->AppendInsertedChild(child, false); - } else { - NodeInfo* ni = child->NodeInfo(); - if (!child->TextIsOnlyWhitespace() && - (ni->NamespaceID() != kNameSpaceID_XUL || - (!ni->Equals(nsGkAtoms::_template) && - !ni->Equals(nsGkAtoms::observes)))) { - // Compatibility hack. For some reason the original XBL - // implementation dropped the content of a binding if any child of - // the bound element didn't match any of the <children> in the - // binding. This became a pseudo-API that we have to maintain. - - // Undo BindAnonymousContent - UnbindAnonymousContent(doc, mContent); - - // Clear out our children elements to avoid dangling references. - ClearInsertionPoints(); - - // Pretend as though there was no content in the binding. - mContent = nullptr; - return; - } - } - } - } - - // Set binding parent on default content if need - if (mDefaultInsertionPoint) { - mDefaultInsertionPoint->MaybeSetupDefaultContent(); - } - for (uint32_t i = 0; i < mInsertionPoints.Length(); ++i) { - mInsertionPoints[i]->MaybeSetupDefaultContent(); - } - - mPrototypeBinding->SetInitialAttributes(mBoundElement, mContent); - } - - // Always check the content element for potential attributes. - // This shorthand hack always happens, even when we didn't - // build anonymous content. - BorrowedAttrInfo attrInfo; - for (uint32_t i = 0; (attrInfo = content->GetAttrInfoAt(i)); ++i) { - int32_t namespaceID = attrInfo.mName->NamespaceID(); - // Hold a strong reference here so that the atom doesn't go away during - // UnsetAttr. - RefPtr<nsAtom> name = attrInfo.mName->LocalName(); - - if (name != nsGkAtoms::includes) { - if (!nsContentUtils::HasNonEmptyAttr(mBoundElement, namespaceID, name)) { - nsAutoString value2; - attrInfo.mValue->ToString(value2); - mBoundElement->SetAttr(namespaceID, name, attrInfo.mName->GetPrefix(), - value2, false); - } - } - - // Conserve space by wiping the attributes off the clone. - // - // FIXME(emilio): It'd be nice to make `mContent` a `RefPtr<Element>`. - if (mContent) mContent->AsElement()->UnsetAttr(namespaceID, name, false); - } -} - -nsIURI* nsXBLBinding::GetSourceDocURI() { - nsIContent* targetContent = - mPrototypeBinding->GetImmediateChild(nsGkAtoms::content); - if (!targetContent) { - return nullptr; - } - - return targetContent->OwnerDoc()->GetDocumentURI(); -} - -XBLChildrenElement* nsXBLBinding::FindInsertionPointFor(nsIContent* aChild) { - // XXX We should get rid of this function as it causes us to traverse the - // binding chain multiple times - if (mContent) { - return FindInsertionPointForInternal(aChild); - } - - return mNextBinding ? mNextBinding->FindInsertionPointFor(aChild) : nullptr; -} - -XBLChildrenElement* nsXBLBinding::FindInsertionPointForInternal( - nsIContent* aChild) { - for (uint32_t i = 0; i < mInsertionPoints.Length(); ++i) { - XBLChildrenElement* point = mInsertionPoints[i]; - if (point->Includes(aChild)) { - return point; - } - } - - return mDefaultInsertionPoint; -} - -void nsXBLBinding::ClearInsertionPoints() { - if (mDefaultInsertionPoint) { - mDefaultInsertionPoint->ClearInsertedChildren(); - } - - for (const auto& insertionPoint : mInsertionPoints) { - insertionPoint->ClearInsertedChildren(); - } -} - -nsAnonymousContentList* nsXBLBinding::GetAnonymousNodeList() { - if (!mContent) { - return mNextBinding ? mNextBinding->GetAnonymousNodeList() : nullptr; - } - - if (!mAnonymousContentList) { - mAnonymousContentList = new nsAnonymousContentList(mContent); - } - - return mAnonymousContentList; -} - -void nsXBLBinding::InstallEventHandlers() { - // Don't install handlers if scripts aren't allowed. - if (AllowScripts()) { - // Fetch the handlers prototypes for this binding. - nsXBLPrototypeHandler* handlerChain = - mPrototypeBinding->GetPrototypeHandlers(); - - if (handlerChain) { - EventListenerManager* manager = - mBoundElement->GetOrCreateListenerManager(); - if (!manager) return; - - bool isChromeDoc = nsContentUtils::IsChromeDoc(mBoundElement->OwnerDoc()); - bool isChromeBinding = mPrototypeBinding->IsChrome(); - nsXBLPrototypeHandler* curr; - for (curr = handlerChain; curr; curr = curr->GetNextHandler()) { - // Fetch the event type. - RefPtr<nsAtom> eventAtom = curr->GetEventName(); - if (!eventAtom || eventAtom == nsGkAtoms::keyup || - eventAtom == nsGkAtoms::keydown || eventAtom == nsGkAtoms::keypress) - continue; - - nsXBLEventHandler* handler = curr->GetEventHandler(); - if (handler) { - // Figure out if we're using capturing or not. - EventListenerFlags flags; - flags.mCapture = (curr->GetPhase() == NS_PHASE_CAPTURING); - - // If this is a command, add it in the system event group - if ((curr->GetType() & - (NS_HANDLER_TYPE_XBL_COMMAND | NS_HANDLER_TYPE_SYSTEM)) && - (isChromeBinding || - mBoundElement->IsInNativeAnonymousSubtree())) { - flags.mInSystemGroup = true; - } - - bool hasAllowUntrustedAttr = curr->HasAllowUntrustedAttr(); - if ((hasAllowUntrustedAttr && curr->AllowUntrustedEvents()) || - (!hasAllowUntrustedAttr && !isChromeDoc)) { - flags.mAllowUntrustedEvents = true; - } - - manager->AddEventListenerByType( - handler, nsDependentAtomString(eventAtom), flags); - } - } - - const nsCOMArray<nsXBLKeyEventHandler>* keyHandlers = - mPrototypeBinding->GetKeyEventHandlers(); - int32_t i; - for (i = 0; i < keyHandlers->Count(); ++i) { - nsXBLKeyEventHandler* handler = keyHandlers->ObjectAt(i); - handler->SetIsBoundToChrome(isChromeDoc); - - nsAutoString type; - handler->GetEventName(type); - - // If this is a command, add it in the system event group, otherwise - // add it to the standard event group. - - // Figure out if we're using capturing or not. - EventListenerFlags flags; - flags.mCapture = (handler->GetPhase() == NS_PHASE_CAPTURING); - - if ((handler->GetType() & - (NS_HANDLER_TYPE_XBL_COMMAND | NS_HANDLER_TYPE_SYSTEM)) && - (isChromeBinding || mBoundElement->IsInNativeAnonymousSubtree())) { - flags.mInSystemGroup = true; - } - - // For key handlers we have to set mAllowUntrustedEvents flag. - // Whether the handling of the event is allowed or not is handled in - // nsXBLKeyEventHandler::HandleEvent - flags.mAllowUntrustedEvents = true; - - manager->AddEventListenerByType(handler, type, flags); - } - } - } - - if (mNextBinding) mNextBinding->InstallEventHandlers(); -} - -nsresult nsXBLBinding::InstallImplementation() { - // Always install the base class properties first, so that - // derived classes can reference the base class properties. - - if (mNextBinding) { - nsresult rv = mNextBinding->InstallImplementation(); - NS_ENSURE_SUCCESS(rv, rv); - } - - // iterate through each property in the prototype's list and install the - // property. - if (AllowScripts()) return mPrototypeBinding->InstallImplementation(this); - - return NS_OK; -} - -void nsXBLBinding::AttributeChanged(nsAtom* aAttribute, int32_t aNameSpaceID, - bool aRemoveFlag, bool aNotify) { - // XXX Change if we ever allow multiple bindings in a chain to contribute - // anonymous content - if (!mContent) { - if (mNextBinding) - mNextBinding->AttributeChanged(aAttribute, aNameSpaceID, aRemoveFlag, - aNotify); - } else { - mPrototypeBinding->AttributeChanged(aAttribute, aNameSpaceID, aRemoveFlag, - mBoundElement, mContent, aNotify); - } -} - -void nsXBLBinding::ExecuteAttachedHandler() { - if (mNextBinding) mNextBinding->ExecuteAttachedHandler(); - - if (AllowScripts()) mPrototypeBinding->BindingAttached(mBoundElement); -} - -void nsXBLBinding::ExecuteDetachedHandler() { - if (AllowScripts()) mPrototypeBinding->BindingDetached(mBoundElement); - - if (mNextBinding) mNextBinding->ExecuteDetachedHandler(); -} - -void nsXBLBinding::UnhookEventHandlers() { - nsXBLPrototypeHandler* handlerChain = - mPrototypeBinding->GetPrototypeHandlers(); - - if (handlerChain) { - EventListenerManager* manager = mBoundElement->GetExistingListenerManager(); - if (!manager) { - return; - } - - bool isChromeBinding = mPrototypeBinding->IsChrome(); - nsXBLPrototypeHandler* curr; - for (curr = handlerChain; curr; curr = curr->GetNextHandler()) { - nsXBLEventHandler* handler = curr->GetCachedEventHandler(); - if (!handler) { - continue; - } - - RefPtr<nsAtom> eventAtom = curr->GetEventName(); - if (!eventAtom || eventAtom == nsGkAtoms::keyup || - eventAtom == nsGkAtoms::keydown || eventAtom == nsGkAtoms::keypress) - continue; - - // Figure out if we're using capturing or not. - EventListenerFlags flags; - flags.mCapture = (curr->GetPhase() == NS_PHASE_CAPTURING); - - // If this is a command, remove it from the system event group, - // otherwise remove it from the standard event group. - - if ((curr->GetType() & - (NS_HANDLER_TYPE_XBL_COMMAND | NS_HANDLER_TYPE_SYSTEM)) && - (isChromeBinding || mBoundElement->IsInNativeAnonymousSubtree())) { - flags.mInSystemGroup = true; - } - - manager->RemoveEventListenerByType( - handler, nsDependentAtomString(eventAtom), flags); - } - - const nsCOMArray<nsXBLKeyEventHandler>* keyHandlers = - mPrototypeBinding->GetKeyEventHandlers(); - int32_t i; - for (i = 0; i < keyHandlers->Count(); ++i) { - nsXBLKeyEventHandler* handler = keyHandlers->ObjectAt(i); - - nsAutoString type; - handler->GetEventName(type); - - // Figure out if we're using capturing or not. - EventListenerFlags flags; - flags.mCapture = (handler->GetPhase() == NS_PHASE_CAPTURING); - - // If this is a command, remove it from the system event group, otherwise - // remove it from the standard event group. - - if ((handler->GetType() & - (NS_HANDLER_TYPE_XBL_COMMAND | NS_HANDLER_TYPE_SYSTEM)) && - (isChromeBinding || mBoundElement->IsInNativeAnonymousSubtree())) { - flags.mInSystemGroup = true; - } - - manager->RemoveEventListenerByType(handler, type, flags); - } - } -} - -void nsXBLBinding::ChangeDocument(Document* aOldDocument, - Document* aNewDocument) { - if (aOldDocument == aNewDocument) return; - - // Now the binding dies. Unhook our prototypes. - if (mPrototypeBinding->HasImplementation()) { - AutoJSAPI jsapi; - // Init might fail here if we've cycle-collected the global object, since - // the Unlink phase of cycle collection happens after JS GC finalization. - // But in that case, we don't care about fixing the prototype chain, since - // everything's going away immediately. - if (jsapi.Init(aOldDocument->GetScopeObject())) { - JSContext* cx = jsapi.cx(); - - JS::Rooted<JSObject*> scriptObject(cx, mBoundElement->GetWrapper()); - if (scriptObject) { - // XXX Stay in sync! What if a layered binding has an - // <interface>?! - // XXXbz what does that comment mean, really? It seems to date - // back to when there was such a thing as an <interface>, whever - // that was... - - // Find the right prototype. - JSAutoRealm ar(cx, scriptObject); - - JS::Rooted<JSObject*> base(cx, scriptObject); - JS::Rooted<JSObject*> proto(cx); - for (; true; base = proto) { // Will break out on null proto - if (!JS_GetPrototype(cx, base, &proto)) { - return; - } - if (!proto) { - break; - } - - if (JS_GetClass(proto) != &gPrototypeJSClass) { - // Clearly not the right class - continue; - } - - RefPtr<nsXBLDocumentInfo> docInfo = - static_cast<nsXBLDocumentInfo*>(::JS_GetPrivate(proto)); - if (!docInfo) { - // Not the proto we seek - continue; - } - - JS::Value protoBinding = ::JS_GetReservedSlot(proto, 0); - - if (protoBinding.toPrivate() != mPrototypeBinding) { - // Not the right binding - continue; - } - - // Alright! This is the right prototype. Pull it out of the - // proto chain. - JS::Rooted<JSObject*> grandProto(cx); - if (!JS_GetPrototype(cx, proto, &grandProto)) { - return; - } - ::JS_SetPrototype(cx, base, grandProto); - break; - } - - mPrototypeBinding->UndefineFields(cx, scriptObject); - - // Don't remove the reference from the document to the - // wrapper here since it'll be removed by the element - // itself when that's taken out of the document. - } - } - } - - // Remove our event handlers - UnhookEventHandlers(); - - { - nsAutoScriptBlocker scriptBlocker; - - // Then do our ancestors. This reverses the construction order, so that at - // all times things are consistent as far as everyone is concerned. - if (mNextBinding) { - mNextBinding->ChangeDocument(aOldDocument, aNewDocument); - } - - // Update the anonymous content. - // XXXbz why not only for style bindings? - if (mContent) { - nsXBLBinding::UnbindAnonymousContent(aOldDocument, mContent); - } - - ClearInsertionPoints(); - } -} - -// Internal helper methods ///////////////////////////////////////////////////// - -// Get or create a WeakMap object on a given XBL-hosting global. -// -// The scheme is as follows. XBL-hosting globals (either privileged content -// Windows or XBL scopes) get two lazily-defined WeakMap properties. Each -// WeakMap is keyed by the grand-proto - i.e. the original prototype of the -// content before it was bound, and the prototype of the class object that we -// splice in. The values in the WeakMap are simple dictionary-style objects, -// mapping from XBL class names to class objects. -static JSObject* GetOrCreateClassObjectMap(JSContext* cx, - JS::Handle<JSObject*> scope, - const char* mapName) { - AssertSameCompartment(cx, scope); - MOZ_ASSERT(JS_IsGlobalObject(scope)); - MOZ_ASSERT(scope == xpc::GetXBLScopeOrGlobal(cx, scope)); - - // First, see if the map is already defined. - JS::Rooted<JS::PropertyDescriptor> desc(cx); - if (!JS_GetOwnPropertyDescriptor(cx, scope, mapName, &desc)) { - return nullptr; - } - if (desc.object() && desc.value().isObject() && - JS::IsWeakMapObject(&desc.value().toObject())) { - return &desc.value().toObject(); - } - - // It's not there. Create and define it. - JS::Rooted<JSObject*> map(cx, JS::NewWeakMapObject(cx)); - if (!map || !JS_DefineProperty(cx, scope, mapName, map, - JSPROP_PERMANENT | JSPROP_READONLY)) { - return nullptr; - } - return map; -} - -static JSObject* GetOrCreateMapEntryForPrototype(JSContext* cx, - JS::Handle<JSObject*> proto) { - AssertSameCompartment(cx, proto); - // We want to hang our class objects off the XBL scope. But since we also - // hoist anonymous content into the XBL scope, this creates the potential for - // tricky collisions, since we can simultaneously have a bound in-content - // node with grand-proto HTMLDivElement and a bound anonymous node whose - // grand-proto is the XBL scope's cross-compartment wrapper to HTMLDivElement. - // Since we have to wrap the WeakMap keys into its scope, this distinction - // would be lost if we don't do something about it. - // - // So we define two maps - one class objects that live in content (prototyped - // to content prototypes), and the other for class objects that live in the - // XBL scope (prototyped to cross-compartment-wrapped content prototypes). - const char* name = xpc::IsInContentXBLScope(proto) - ? "__ContentClassObjectMap__" - : "__XBLClassObjectMap__"; - - // Now, enter the XBL scope, since that's where we need to operate, and wrap - // the proto accordingly. We hang the map off of the content XBL scope for - // content, and the Window for chrome (whether add-ons are involved or not). - JS::Rooted<JSObject*> scope( - cx, xpc::GetXBLScopeOrGlobal(cx, JS::CurrentGlobalOrNull(cx))); - NS_ENSURE_TRUE(scope, nullptr); - MOZ_ASSERT(JS_IsGlobalObject(scope)); - - JS::Rooted<JSObject*> wrappedProto(cx, proto); - JSAutoRealm ar(cx, scope); - if (!JS_WrapObject(cx, &wrappedProto)) { - return nullptr; - } - - // Grab the appropriate WeakMap. - JS::Rooted<JSObject*> map(cx, GetOrCreateClassObjectMap(cx, scope, name)); - if (!map) { - return nullptr; - } - - // See if we already have a map entry for that prototype. - JS::Rooted<JS::Value> val(cx); - if (!JS::GetWeakMapEntry(cx, map, wrappedProto, &val)) { - return nullptr; - } - if (val.isObject()) { - return &val.toObject(); - } - - // We don't have an entry. Create one and stick it in the map. - JS::Rooted<JSObject*> entry(cx); - entry = JS_NewObjectWithGivenProto(cx, nullptr, nullptr); - if (!entry) { - return nullptr; - } - JS::Rooted<JS::Value> entryVal(cx, JS::ObjectValue(*entry)); - if (!JS::SetWeakMapEntry(cx, map, wrappedProto, entryVal)) { - NS_WARNING( - "SetWeakMapEntry failed, probably due to non-preservable WeakMap " - "key. XBL binding will fail for this element."); - return nullptr; - } - return entry; -} - -static nsXBLPrototypeBinding* GetProtoBindingFromClassObject(JSObject* obj) { - MOZ_ASSERT(JS_GetClass(obj) == &gPrototypeJSClass); - return static_cast<nsXBLPrototypeBinding*>( - ::JS_GetReservedSlot(obj, 0).toPrivate()); -} - -// static -nsresult nsXBLBinding::DoInitJSClass(JSContext* cx, JS::Handle<JSObject*> obj, - const nsString& aClassName, - nsXBLPrototypeBinding* aProtoBinding, - JS::MutableHandle<JSObject*> aClassObject, - bool* aNew) { - MOZ_ASSERT(obj); - - // Note that, now that NAC reflectors are created in the XBL scope, the - // reflector is not necessarily same-compartment with the document. So we'll - // end up creating a separate instance of the oddly-named XBL class object - // and defining it as a property on the XBL scope's global. This works fine, - // but we need to make sure never to assume that the the reflector and - // prototype are same-compartment with the bound document. - JS::Rooted<JSObject*> global(cx, JS::GetNonCCWObjectGlobal(obj)); - - // We must be in obj's realm. - MOZ_ASSERT(JS::CurrentGlobalOrNull(cx) == global); - - // We never store class objects in add-on scopes. - JS::Rooted<JSObject*> xblScope(cx, xpc::GetXBLScopeOrGlobal(cx, global)); - NS_ENSURE_TRUE(xblScope, NS_ERROR_UNEXPECTED); - - JS::Rooted<JSObject*> parent_proto(cx); - { - JS::RootedObject wrapped(cx, obj); - JSAutoRealm ar(cx, xblScope); - if (!JS_WrapObject(cx, &wrapped)) { - return NS_ERROR_FAILURE; - } - if (!JS_GetPrototype(cx, wrapped, &parent_proto)) { - return NS_ERROR_FAILURE; - } - } - if (!JS_WrapObject(cx, &parent_proto)) { - return NS_ERROR_FAILURE; - } - - // Get the map entry for the parent prototype. In the one-off case that the - // parent prototype is null, we somewhat hackily just use the WeakMap itself - // as a property holder. - JS::Rooted<JSObject*> holder(cx); - if (parent_proto) { - holder = GetOrCreateMapEntryForPrototype(cx, parent_proto); - } else { - JSAutoRealm innerAR(cx, xblScope); - holder = - GetOrCreateClassObjectMap(cx, xblScope, "__ContentClassObjectMap__"); - } - if (NS_WARN_IF(!holder)) { - return NS_ERROR_FAILURE; - } - js::AssertSameCompartment(holder, xblScope); - JSAutoRealm ar(cx, holder); - - // Look up the class on the property holder. The only properties on the - // holder should be class objects. If we don't find the class object, we need - // to create and define it. - JS::Rooted<JSObject*> proto(cx); - JS::Rooted<JS::PropertyDescriptor> desc(cx); - if (!JS_GetOwnUCPropertyDescriptor(cx, holder, aClassName.get(), - aClassName.Length(), &desc)) { - return NS_ERROR_OUT_OF_MEMORY; - } - *aNew = !desc.object(); - if (desc.object()) { - proto = &desc.value().toObject(); - DebugOnly<nsXBLPrototypeBinding*> cachedBinding = - GetProtoBindingFromClassObject(js::UncheckedUnwrap(proto)); - MOZ_ASSERT(cachedBinding == aProtoBinding); - } else { - // We need to create the prototype. First, enter the realm where it's - // going to live, and create it. - JSAutoRealm ar2(cx, global); - proto = JS_NewObjectWithGivenProto(cx, &gPrototypeJSClass, parent_proto); - if (!proto) { - return NS_ERROR_OUT_OF_MEMORY; - } - - // Keep this proto binding alive while we're alive. Do this first so that - // we can guarantee that in XBLFinalize this will be non-null. - // Note that we can't just store aProtoBinding in the private and - // addref/release the nsXBLDocumentInfo through it, because cycle - // collection doesn't seem to work right if the private is not an - // nsISupports. - nsXBLDocumentInfo* docInfo = aProtoBinding->XBLDocumentInfo(); - ::JS_SetPrivate(proto, docInfo); - NS_ADDREF(docInfo); - JS_SetReservedSlot(proto, 0, JS::PrivateValue(aProtoBinding)); - - // Don't collect the proto while recording/replaying, to avoid - // non-deterministically releasing the docInfo reference. - recordreplay::HoldJSObject(proto); - - // Next, enter the realm of the property holder, wrap the proto, and - // stick it on. - JSAutoRealm ar3(cx, holder); - if (!JS_WrapObject(cx, &proto) || - !JS_DefineUCProperty(cx, holder, aClassName.get(), -1, proto, - JSPROP_READONLY | JSPROP_PERMANENT)) { - return NS_ERROR_OUT_OF_MEMORY; - } - } - - // Whew. We have the proto. Wrap it back into the realm of |obj|, - // splice it in, and return it. - JSAutoRealm ar4(cx, obj); - if (!JS_WrapObject(cx, &proto) || !JS_SetPrototype(cx, obj, proto)) { - return NS_ERROR_FAILURE; - } - aClassObject.set(proto); - return NS_OK; -} - -bool nsXBLBinding::AllowScripts() { - return mBoundElement && mPrototypeBinding->GetAllowScripts(); -} - -nsXBLBinding* nsXBLBinding::RootBinding() { - if (mNextBinding) return mNextBinding->RootBinding(); - - return this; -} - -bool nsXBLBinding::ResolveAllFields(JSContext* cx, - JS::Handle<JSObject*> obj) const { - if (!mPrototypeBinding->ResolveAllFields(cx, obj)) { - return false; - } - - if (mNextBinding) { - return mNextBinding->ResolveAllFields(cx, obj); - } - - return true; -} - -bool nsXBLBinding::LookupMember( - JSContext* aCx, JS::Handle<jsid> aId, - JS::MutableHandle<JS::PropertyDescriptor> aDesc) { - // We should never enter this function with a pre-filled property descriptor. - MOZ_ASSERT(!aDesc.object()); - - // Get the string as an nsString before doing anything, so we can make - // convenient comparisons during our search. - if (!JSID_IS_STRING(aId)) { - return true; - } - nsAutoJSString name; - if (!name.init(aCx, JSID_TO_STRING(aId))) { - return false; - } - - // We have a weak reference to our bound element, so make sure it's alive. - if (!mBoundElement || !mBoundElement->GetWrapper()) { - return false; - } - - // Get the scope of mBoundElement and the associated XBL scope. We should only - // be calling into this machinery if we're running in a separate XBL scope. - // - // Note that we only end up in LookupMember for XrayWrappers from XBL scopes - // into content. So for NAC reflectors that live in the XBL scope, we should - // never get here. But on the off-chance that someone adds new callsites to - // LookupMember, we do a release-mode assertion as belt-and-braces. - // We do a release-mode assertion here to be extra safe. - // - // This code is only called for content XBL, so we don't have to worry about - // add-on scopes here. - JS::Rooted<JSObject*> boundScope( - aCx, JS::GetNonCCWObjectGlobal(mBoundElement->GetWrapper())); - MOZ_RELEASE_ASSERT(!xpc::IsInContentXBLScope(boundScope)); - JS::Rooted<JSObject*> xblScope(aCx, xpc::GetXBLScope(aCx, boundScope)); - NS_ENSURE_TRUE(xblScope, false); - MOZ_ASSERT(boundScope != xblScope); - - // Enter the xbl scope and invoke the internal version. - { - JSAutoRealm ar(aCx, xblScope); - JS::Rooted<jsid> id(aCx, aId); - if (!LookupMemberInternal(aCx, name, id, aDesc, xblScope)) { - return false; - } - } - - // Wrap into the caller's scope. - return JS_WrapPropertyDescriptor(aCx, aDesc); -} - -bool nsXBLBinding::LookupMemberInternal( - JSContext* aCx, nsString& aName, JS::Handle<jsid> aNameAsId, - JS::MutableHandle<JS::PropertyDescriptor> aDesc, - JS::Handle<JSObject*> aXBLScope) { - // First, see if we have an implementation. If we don't, it means that this - // binding doesn't have a class object, and thus doesn't have any members. - // Skip it. - if (!PrototypeBinding()->HasImplementation()) { - if (!mNextBinding) { - return true; - } - return mNextBinding->LookupMemberInternal(aCx, aName, aNameAsId, aDesc, - aXBLScope); - } - - // Find our class object. It's in a protected scope and permanent just in - // case, so should be there no matter what. - JS::Rooted<JS::Value> classObject(aCx); - if (!JS_GetUCProperty(aCx, aXBLScope, PrototypeBinding()->ClassName().get(), - -1, &classObject)) { - return false; - } - - // The bound element may have been adoped by a document and have a different - // wrapper (and different xbl scope) than when the binding was applied, in - // this case getting the class object will fail. Behave as if the class - // object did not exist. - if (classObject.isUndefined()) { - return true; - } - - MOZ_ASSERT(classObject.isObject()); - - // Look for the property on this binding. If it's not there, try the next - // binding on the chain. - nsXBLProtoImpl* impl = mPrototypeBinding->GetImplementation(); - JS::Rooted<JSObject*> object(aCx, &classObject.toObject()); - if (impl && !impl->LookupMember(aCx, aName, aNameAsId, aDesc, object)) { - return false; - } - if (aDesc.object() || !mNextBinding) { - return true; - } - - return mNextBinding->LookupMemberInternal(aCx, aName, aNameAsId, aDesc, - aXBLScope); -} - -bool nsXBLBinding::HasField(nsString& aName) { - // See if this binding has such a field. - return mPrototypeBinding->FindField(aName) || - (mNextBinding && mNextBinding->HasField(aName)); -} - -void nsXBLBinding::MarkForDeath() { - mMarkedForDeath = true; - ExecuteDetachedHandler(); -} - -bool nsXBLBinding::ImplementsInterface(REFNSIID aIID) const { - return mPrototypeBinding->ImplementsInterface(aIID) || - (mNextBinding && mNextBinding->ImplementsInterface(aIID)); -}
deleted file mode 100644 --- a/dom/xbl/nsXBLBinding.h +++ /dev/null @@ -1,176 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* 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 nsXBLBinding_h_ -#define nsXBLBinding_h_ - -#include "nsXBLService.h" -#include "nsCOMPtr.h" -#include "nsINodeList.h" -#include "nsClassHashtable.h" -#include "nsTArray.h" -#include "nsCycleCollectionParticipant.h" -#include "nsISupportsImpl.h" -#include "js/TypeDecls.h" - -class nsXBLPrototypeBinding; -class nsIContent; -class nsAtom; -struct RawServoAuthorStyles; - -namespace mozilla { -namespace dom { -class Document; -class XBLChildrenElement; -} // namespace dom -} // namespace mozilla - -class nsAnonymousContentList; - -// *********************************************************************/ -// The XBLBinding class - -class nsXBLBinding final { - public: - explicit nsXBLBinding(nsXBLPrototypeBinding* aProtoBinding); - - /** - * XBLBindings are refcounted. They are held onto in 3 ways: - * 1. The binding manager's binding table holds onto all bindings that are - * currently attached to a content node. - * 2. Bindings hold onto their base binding. This is important since - * the base binding itself may not be attached to anything. - * 3. The binding manager holds an additional reference to bindings - * which are queued to fire their constructors. - */ - - NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsXBLBinding) - - NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsXBLBinding) - - nsXBLPrototypeBinding* PrototypeBinding() const { return mPrototypeBinding; } - nsIContent* GetAnonymousContent() { return mContent.get(); } - nsXBLBinding* GetBindingWithContent(); - - nsXBLBinding* GetBaseBinding() const { return mNextBinding; } - void SetBaseBinding(nsXBLBinding* aBinding); - - mozilla::dom::Element* GetBoundElement() { return mBoundElement; } - void SetBoundElement(mozilla::dom::Element* aElement); - - /* - * Does a lookup for a method or attribute provided by one of the bindings' - * prototype implementation. If found, |desc| will be set up appropriately, - * and wrapped into cx->compartment. - * - * May only be called when XBL code is being run in a separate scope, because - * otherwise we don't have untainted data with which to do a proper lookup. - */ - bool LookupMember(JSContext* aCx, JS::Handle<jsid> aId, - JS::MutableHandle<JS::PropertyDescriptor> aDesc); - - /* - * Determines whether the binding has a field with the given name. - */ - bool HasField(nsString& aName); - - protected: - ~nsXBLBinding(); - - /* - * Internal version. Requires that aCx is in appropriate xbl scope. - */ - bool LookupMemberInternal(JSContext* aCx, nsString& aName, - JS::Handle<jsid> aNameAsId, - JS::MutableHandle<JS::PropertyDescriptor> aDesc, - JS::Handle<JSObject*> aXBLScope); - - public: - void MarkForDeath(); - bool MarkedForDeath() const { return mMarkedForDeath; } - - bool ImplementsInterface(REFNSIID aIID) const; - - void GenerateAnonymousContent(); - void BindAnonymousContent(nsIContent* aAnonParent, nsIContent* aElement); - static void UnbindAnonymousContent(mozilla::dom::Document* aDocument, - nsIContent* aAnonParent, - bool aNullParent = true); - void InstallEventHandlers(); - nsresult InstallImplementation(); - - void ExecuteAttachedHandler(); - void ExecuteDetachedHandler(); - void UnhookEventHandlers(); - - nsXBLBinding* RootBinding(); - - // Resolve all the fields for this binding and all ancestor bindings on the - // object |obj|. False return means a JS exception was set. - bool ResolveAllFields(JSContext* cx, JS::Handle<JSObject*> obj) const; - - void AttributeChanged(nsAtom* aAttribute, int32_t aNameSpaceID, - bool aRemoveFlag, bool aNotify); - - void ChangeDocument(mozilla::dom::Document* aOldDocument, - mozilla::dom::Document* aNewDocument); - - const RawServoAuthorStyles* GetServoStyles() const; - - static nsresult DoInitJSClass(JSContext* cx, JS::Handle<JSObject*> obj, - const nsString& aClassName, - nsXBLPrototypeBinding* aProtoBinding, - JS::MutableHandle<JSObject*> aClassObject, - bool* aNew); - - bool AllowScripts(); - - mozilla::dom::XBLChildrenElement* FindInsertionPointFor(nsIContent* aChild); - - bool HasFilteredInsertionPoints() { return !mInsertionPoints.IsEmpty(); } - - mozilla::dom::XBLChildrenElement* GetDefaultInsertionPoint() { - return mDefaultInsertionPoint; - } - - // Removes all inserted node from <xbl:children> insertion points under us. - void ClearInsertionPoints(); - - // Returns a live node list that iterates over the anonymous nodes generated - // by this binding. - nsAnonymousContentList* GetAnonymousNodeList(); - - nsIURI* GetSourceDocURI(); - - // MEMBER VARIABLES - protected: - bool mMarkedForDeath; - - nsXBLPrototypeBinding* - mPrototypeBinding; // Weak, but we're holding a ref to the docinfo - nsCOMPtr<nsIContent> - mContent; // Strong. Our anonymous content stays around with us. - RefPtr<nsXBLBinding> mNextBinding; // Strong. The derived binding owns the - // base class bindings. - - mozilla::dom::Element* - mBoundElement; // [WEAK] We have a reference, but we don't own it. - - // The <xbl:children> elements that we found in our <xbl:content> when we - // processed this binding. The default insertion point has no includes - // attribute and all other insertion points must have at least one includes - // attribute. These points must be up-to-date with respect to their parent's - // children, even if their parent has another binding attached to it, - // preventing us from rendering their contents directly. - RefPtr<mozilla::dom::XBLChildrenElement> mDefaultInsertionPoint; - nsTArray<RefPtr<mozilla::dom::XBLChildrenElement> > mInsertionPoints; - RefPtr<nsAnonymousContentList> mAnonymousContentList; - - mozilla::dom::XBLChildrenElement* FindInsertionPointForInternal( - nsIContent* aChild); -}; - -#endif // nsXBLBinding_h_
deleted file mode 100644 --- a/dom/xbl/nsXBLContentSink.cpp +++ /dev/null @@ -1,802 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* 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/. */ - -#include "mozilla/ArrayUtils.h" - -#include "nsXBLContentSink.h" -#include "mozilla/dom/Document.h" -#include "nsBindingManager.h" -#include "nsGkAtoms.h" -#include "nsNameSpaceManager.h" -#include "nsIURI.h" -#include "nsTextFragment.h" -#ifdef MOZ_XUL -# include "nsXULElement.h" -#endif -#include "nsXBLProtoImplProperty.h" -#include "nsXBLProtoImplMethod.h" -#include "nsXBLProtoImplField.h" -#include "nsXBLPrototypeBinding.h" -#include "nsContentUtils.h" -#include "nsIConsoleService.h" -#include "nsIScriptError.h" -#include "nsNodeInfoManager.h" -#include "nsIPrincipal.h" -#include "mozilla/dom/Element.h" - -using namespace mozilla; -using namespace mozilla::dom; - -nsresult NS_NewXBLContentSink(nsIXMLContentSink** aResult, Document* aDoc, - nsIURI* aURI, nsISupports* aContainer) { - NS_ENSURE_ARG_POINTER(aResult); - - RefPtr<nsXBLContentSink> it = new nsXBLContentSink(); - nsresult rv = it->Init(aDoc, aURI, aContainer); - NS_ENSURE_SUCCESS(rv, rv); - - it.forget(aResult); - return NS_OK; -} - -nsXBLContentSink::nsXBLContentSink() - : mState(eXBL_InDocument), - mSecondaryState(eXBL_None), - mDocInfo(nullptr), - mIsChromeOrResource(false), - mFoundFirstBinding(false), - mBinding(nullptr), - mHandler(nullptr), - mImplementation(nullptr), - mImplMember(nullptr), - mImplField(nullptr), - mProperty(nullptr), - mMethod(nullptr), - mField(nullptr) { - mPrettyPrintXML = false; -} - -nsXBLContentSink::~nsXBLContentSink() {} - -nsresult nsXBLContentSink::Init(Document* aDoc, nsIURI* aURI, - nsISupports* aContainer) { - nsresult rv; - rv = nsXMLContentSink::Init(aDoc, aURI, aContainer, nullptr); - return rv; -} - -void nsXBLContentSink::MaybeStartLayout(bool aIgnorePendingSheets) {} - -nsresult nsXBLContentSink::FlushText(bool aReleaseTextNode) { - if (mTextLength != 0) { - const nsAString& text = Substring(mText, mText + mTextLength); - if (mState == eXBL_InHandlers) { - NS_ASSERTION(mBinding, "Must have binding here"); - // Get the text and add it to the event handler. - if (mSecondaryState == eXBL_InHandler) mHandler->AppendHandlerText(text); - mTextLength = 0; - return NS_OK; - } else if (mState == eXBL_InImplementation) { - NS_ASSERTION(mBinding, "Must have binding here"); - if (mSecondaryState == eXBL_InConstructor || - mSecondaryState == eXBL_InDestructor) { - // Construct a method for the constructor/destructor. - nsXBLProtoImplMethod* method; - if (mSecondaryState == eXBL_InConstructor) - method = mBinding->GetConstructor(); - else - method = mBinding->GetDestructor(); - - // Get the text and add it to the constructor/destructor. - method->AppendBodyText(text); - } else if (mSecondaryState == eXBL_InGetter || - mSecondaryState == eXBL_InSetter) { - // Get the text and add it to the getter/setter - if (mSecondaryState == eXBL_InGetter) - mProperty->AppendGetterText(text); - else - mProperty->AppendSetterText(text); - } else if (mSecondaryState == eXBL_InBody) { - // Get the text and add it to the method - if (mMethod) mMethod->AppendBodyText(text); - } else if (mSecondaryState == eXBL_InField) { - // Get the text and add it to the method - if (mField) mField->AppendFieldText(text); - } - mTextLength = 0; - return NS_OK; - } - - nsIContent* content = GetCurrentContent(); - if (content && (content->NodeInfo()->NamespaceEquals(kNameSpaceID_XBL) || - (content->IsXULElement() && - !content->IsAnyOfXULElements(nsGkAtoms::label, - nsGkAtoms::description)))) { - bool isWS = true; - if (mTextLength > 0) { - const char16_t* cp = mText; - const char16_t* end = mText + mTextLength; - while (cp < end) { - char16_t ch = *cp++; - if (!dom::IsSpaceCharacter(ch)) { - isWS = false; - break; - } - } - } - - if (isWS && mTextLength > 0) { - mTextLength = 0; - // Make sure to drop the textnode, if any - return nsXMLContentSink::FlushText(aReleaseTextNode); - } - } - } - - return nsXMLContentSink::FlushText(aReleaseTextNode); -} - -NS_IMETHODIMP -nsXBLContentSink::ReportError(const char16_t* aErrorText, - const char16_t* aSourceText, - nsIScriptError* aError, bool* _retval) { - MOZ_ASSERT(aError && aSourceText && aErrorText, "Check arguments!!!"); - - // XXX FIXME This function overrides and calls on - // nsXMLContentSink::ReportError, and probably should die. See bug 347826. - - // XXX We should make sure the binding has no effect, but that it also - // gets destroyed properly without leaking. Perhaps we should even - // ensure that the content that was bound is displayed with no - // binding. - -#ifdef DEBUG - // Report the error to stderr. - fprintf(stderr, "\n%s\n%s\n\n", NS_LossyConvertUTF16toASCII(aErrorText).get(), - NS_LossyConvertUTF16toASCII(aSourceText).get()); -#endif - - // Most of what this does won't be too useful, but whatever... - // nsXMLContentSink::ReportError will handle the console logging. - return nsXMLContentSink::ReportError(aErrorText, aSourceText, aError, - _retval); -} - -nsresult nsXBLContentSink::ReportUnexpectedElement(nsAtom* aElementName, - uint32_t aLineNumber) { - // XXX we should really somehow stop the parse and drop the binding - // instead of just letting the XML sink build the content model like - // we do... - mState = eXBL_Error; - AutoTArray<nsString, 1> params; - aElementName->ToString(*params.AppendElement()); - - return nsContentUtils::ReportToConsole( - nsIScriptError::errorFlag, NS_LITERAL_CSTRING("XBL Content Sink"), - mDocument, nsContentUtils::eXBL_PROPERTIES, "UnexpectedElement", params, - nullptr, EmptyString() /* source line */, aLineNumber); -} - -void nsXBLContentSink::AddMember(nsXBLProtoImplMember* aMember) { - // Add this member to our chain. - if (mImplMember) - mImplMember->SetNext( - aMember); // Already have a chain. Just append to the end. - else - mImplementation->SetMemberList( - aMember); // We're the first member in the chain. - - mImplMember = aMember; // Adjust our pointer to point to the new last member - // in the chain. -} - -void nsXBLContentSink::AddField(nsXBLProtoImplField* aField) { - // Add this field to our chain. - if (mImplField) - mImplField->SetNext( - aField); // Already have a chain. Just append to the end. - else - mImplementation->SetFieldList( - aField); // We're the first member in the chain. - - mImplField = aField; // Adjust our pointer to point to the new last field in - // the chain. -} - -NS_IMETHODIMP -nsXBLContentSink::HandleStartElement(const char16_t* aName, - const char16_t** aAtts, - uint32_t aAttsCount, uint32_t aLineNumber, - uint32_t aColumnNumber) { - nsresult rv = nsXMLContentSink::HandleStartElement( - aName, aAtts, aAttsCount, aLineNumber, aColumnNumber); - if (NS_FAILED(rv)) return rv; - - if (mState == eXBL_InBinding && !mBinding) { - rv = ConstructBinding(aLineNumber); - if (NS_FAILED(rv)) return rv; - - // mBinding may still be null, if the binding had no id. If so, - // we'll deal with that later in the sink. - } - - return rv; -} - -NS_IMETHODIMP -nsXBLContentSink::HandleEndElement(const char16_t* aName) { - FlushText(); - - if (mState != eXBL_InDocument) { - int32_t nameSpaceID; - RefPtr<nsAtom> prefix, localName; - nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix), - getter_AddRefs(localName), &nameSpaceID); - - if (nameSpaceID == kNameSpaceID_XBL) { - if (mState == eXBL_Error) { - // Check whether we've opened this tag before; we may not have if - // it was a real XBL tag before the error occurred. - if (!GetCurrentContent()->NodeInfo()->Equals(localName, nameSpaceID)) { - // OK, this tag was never opened as far as the XML sink is - // concerned. Just drop the HandleEndElement - return NS_OK; - } - } else if (mState == eXBL_InHandlers) { - if (localName == nsGkAtoms::handlers) { - mState = eXBL_InBinding; - mHandler = nullptr; - } else if (localName == nsGkAtoms::handler) - mSecondaryState = eXBL_None; - return NS_OK; - } else if (mState == eXBL_InImplementation) { - if (localName == nsGkAtoms::implementation) - mState = eXBL_InBinding; - else if (localName == nsGkAtoms::property) { - mSecondaryState = eXBL_None; - mProperty = nullptr; - } else if (localName == nsGkAtoms::method) { - mSecondaryState = eXBL_None; - mMethod = nullptr; - } else if (localName == nsGkAtoms::field) { - mSecondaryState = eXBL_None; - mField = nullptr; - } else if (localName == nsGkAtoms::constructor || - localName == nsGkAtoms::destructor) - mSecondaryState = eXBL_None; - else if (localName == nsGkAtoms::getter || - localName == nsGkAtoms::setter) - mSecondaryState = eXBL_InProperty; - else if (localName == nsGkAtoms::parameter || - localName == nsGkAtoms::body) - mSecondaryState = eXBL_InMethod; - return NS_OK; - } else if (mState == eXBL_InBindings && - localName == nsGkAtoms::bindings) { - mState = eXBL_InDocument; - } - - nsresult rv = nsXMLContentSink::HandleEndElement(aName); - if (NS_FAILED(rv)) return rv; - - if (mState == eXBL_InBinding && localName == nsGkAtoms::binding) { - mState = eXBL_InBindings; - if (mBinding) { // See comment in HandleStartElement() - mBinding->Initialize(); - mBinding = nullptr; // Clear our current binding ref. - } - } - - return NS_OK; - } - } - - return nsXMLContentSink::HandleEndElement(aName); -} - -NS_IMETHODIMP -nsXBLContentSink::HandleCDataSection(const char16_t* aData, uint32_t aLength) { - if (mState == eXBL_InHandlers || mState == eXBL_InImplementation) - return AddText(aData, aLength); - return nsXMLContentSink::HandleCDataSection(aData, aLength); -} - -#define ENSURE_XBL_STATE(_cond) \ - PR_BEGIN_MACRO \ - if (!(_cond)) { \ - ReportUnexpectedElement(aTagName, aLineNumber); \ - return true; \ - } \ - PR_END_MACRO - -bool nsXBLContentSink::OnOpenContainer(const char16_t** aAtts, - uint32_t aAttsCount, - int32_t aNameSpaceID, nsAtom* aTagName, - uint32_t aLineNumber) { - if (mState == eXBL_Error) { - return true; - } - - if (aNameSpaceID != kNameSpaceID_XBL) { - // Construct non-XBL nodes - return true; - } - - bool ret = true; - if (aTagName == nsGkAtoms::bindings) { - ENSURE_XBL_STATE(mState == eXBL_InDocument); - - NS_ASSERTION(mDocument, "Must have a document!"); - RefPtr<nsXBLDocumentInfo> info = new nsXBLDocumentInfo(mDocument); - - // We keep a weak ref. We're creating a cycle between doc/binding - // manager/doc info. - mDocInfo = info; - - if (!mDocInfo) { - mState = eXBL_Error; - return true; - } - - mDocument->BindingManager()->PutXBLDocumentInfo(mDocInfo); - - nsIURI* uri = mDocument->GetDocumentURI(); - - mIsChromeOrResource = uri->SchemeIs("chrome") || uri->SchemeIs("resource"); - - mState = eXBL_InBindings; - } else if (aTagName == nsGkAtoms::binding) { - ENSURE_XBL_STATE(mState == eXBL_InBindings); - mState = eXBL_InBinding; - } else if (aTagName == nsGkAtoms::handlers) { - ENSURE_XBL_STATE(mState == eXBL_InBinding && mBinding); - mState = eXBL_InHandlers; - ret = false; - } else if (aTagName == nsGkAtoms::handler) { - ENSURE_XBL_STATE(mState == eXBL_InHandlers); - mSecondaryState = eXBL_InHandler; - ConstructHandler(aAtts, aLineNumber); - ret = false; - } else if (aTagName == nsGkAtoms::implementation) { - ENSURE_XBL_STATE(mState == eXBL_InBinding && mBinding); - mState = eXBL_InImplementation; - ConstructImplementation(aAtts); - // Note that this mState will cause us to return false, so no need - // to set ret to false. - } else if (aTagName == nsGkAtoms::constructor) { - ENSURE_XBL_STATE(mState == eXBL_InImplementation && - mSecondaryState == eXBL_None); - NS_ASSERTION(mBinding, "Must have binding here"); - - mSecondaryState = eXBL_InConstructor; - nsAutoString name; - if (!mCurrentBindingID.IsEmpty()) { - name.Assign(mCurrentBindingID); - name.AppendLiteral("_XBL_Constructor"); - } else { - name.AppendLiteral("XBL_Constructor"); - } - nsXBLProtoImplAnonymousMethod* newMethod = - new nsXBLProtoImplAnonymousMethod(name.get()); - newMethod->SetLineNumber(aLineNumber); - mBinding->SetConstructor(newMethod); - AddMember(newMethod); - } else if (aTagName == nsGkAtoms::destructor) { - ENSURE_XBL_STATE(mState == eXBL_InImplementation && - mSecondaryState == eXBL_None); - NS_ASSERTION(mBinding, "Must have binding here"); - mSecondaryState = eXBL_InDestructor; - nsAutoString name; - if (!mCurrentBindingID.IsEmpty()) { - name.Assign(mCurrentBindingID); - name.AppendLiteral("_XBL_Destructor"); - } else { - name.AppendLiteral("XBL_Destructor"); - } - nsXBLProtoImplAnonymousMethod* newMethod = - new nsXBLProtoImplAnonymousMethod(name.get()); - newMethod->SetLineNumber(aLineNumber); - mBinding->SetDestructor(newMethod); - AddMember(newMethod); - } else if (aTagName == nsGkAtoms::field) { - ENSURE_XBL_STATE(mState == eXBL_InImplementation && - mSecondaryState == eXBL_None); - NS_ASSERTION(mBinding, "Must have binding here"); - mSecondaryState = eXBL_InField; - ConstructField(aAtts, aLineNumber); - } else if (aTagName == nsGkAtoms::property) { - ENSURE_XBL_STATE(mState == eXBL_InImplementation && - mSecondaryState == eXBL_None); - NS_ASSERTION(mBinding, "Must have binding here"); - mSecondaryState = eXBL_InProperty; - ConstructProperty(aAtts, aLineNumber); - } else if (aTagName == nsGkAtoms::getter) { - ENSURE_XBL_STATE(mSecondaryState == eXBL_InProperty && mProperty); - NS_ASSERTION(mState == eXBL_InImplementation, "Unexpected state"); - mProperty->SetGetterLineNumber(aLineNumber); - mSecondaryState = eXBL_InGetter; - } else if (aTagName == nsGkAtoms::setter) { - ENSURE_XBL_STATE(mSecondaryState == eXBL_InProperty && mProperty); - NS_ASSERTION(mState == eXBL_InImplementation, "Unexpected state"); - mProperty->SetSetterLineNumber(aLineNumber); - mSecondaryState = eXBL_InSetter; - } else if (aTagName == nsGkAtoms::method) { - ENSURE_XBL_STATE(mState == eXBL_InImplementation && - mSecondaryState == eXBL_None); - NS_ASSERTION(mBinding, "Must have binding here"); - mSecondaryState = eXBL_InMethod; - ConstructMethod(aAtts); - } else if (aTagName == nsGkAtoms::parameter) { - ENSURE_XBL_STATE(mSecondaryState == eXBL_InMethod && mMethod); - NS_ASSERTION(mState == eXBL_InImplementation, "Unexpected state"); - ConstructParameter(aAtts); - } else if (aTagName == nsGkAtoms::body) { - ENSURE_XBL_STATE(mSecondaryState == eXBL_InMethod && mMethod); - NS_ASSERTION(mState == eXBL_InImplementation, "Unexpected state"); - // stash away the line number - mMethod->SetLineNumber(aLineNumber); - mSecondaryState = eXBL_InBody; - } - - return ret && mState != eXBL_InImplementation; -} - -#undef ENSURE_XBL_STATE - -nsresult nsXBLContentSink::ConstructBinding(uint32_t aLineNumber) { - // This is only called from HandleStartElement, so it'd better be an element. - RefPtr<Element> binding = GetCurrentContent()->AsElement(); - binding->GetAttr(kNameSpaceID_None, nsGkAtoms::id, mCurrentBindingID); - NS_ConvertUTF16toUTF8 cid(mCurrentBindingID); - - nsresult rv = NS_OK; - - // Don't create a binding with no id. nsXBLPrototypeBinding::Read also - // performs this check. - if (!cid.IsEmpty()) { - mBinding = new nsXBLPrototypeBinding(); - - rv = mBinding->Init(cid, mDocInfo, binding, !mFoundFirstBinding); - if (NS_SUCCEEDED(rv) && - NS_SUCCEEDED(mDocInfo->SetPrototypeBinding(cid, mBinding))) { - if (!mFoundFirstBinding) { - mFoundFirstBinding = true; - mDocInfo->SetFirstPrototypeBinding(mBinding); - } - binding->UnsetAttr(kNameSpaceID_None, nsGkAtoms::id, false); - } else { - delete mBinding; - mBinding = nullptr; - } - } else { - nsContentUtils::ReportToConsole( - nsIScriptError::errorFlag, NS_LITERAL_CSTRING("XBL Content Sink"), - nullptr, nsContentUtils::eXBL_PROPERTIES, "MissingIdAttr", - nsTArray<nsString>(), mDocumentURI, EmptyString(), aLineNumber); - } - - return rv; -} - -static bool FindValue(const char16_t** aAtts, nsAtom* aAtom, - const char16_t** aResult) { - RefPtr<nsAtom> prefix, localName; - for (; *aAtts; aAtts += 2) { - int32_t nameSpaceID; - nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix), - getter_AddRefs(localName), &nameSpaceID); - - // Is this attribute one of the ones we care about? - if (nameSpaceID == kNameSpaceID_None && localName == aAtom) { - *aResult = aAtts[1]; - - return true; - } - } - - return false; -} - -void nsXBLContentSink::ConstructHandler(const char16_t** aAtts, - uint32_t aLineNumber) { - const char16_t* event = nullptr; - const char16_t* modifiers = nullptr; - const char16_t* button = nullptr; - const char16_t* clickcount = nullptr; - const char16_t* keycode = nullptr; - const char16_t* charcode = nullptr; - const char16_t* phase = nullptr; - const char16_t* command = nullptr; - const char16_t* action = nullptr; - const char16_t* group = nullptr; - const char16_t* preventdefault = nullptr; - const char16_t* allowuntrusted = nullptr; - - RefPtr<nsAtom> prefix, localName; - for (; *aAtts; aAtts += 2) { - int32_t nameSpaceID; - nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix), - getter_AddRefs(localName), &nameSpaceID); - - if (nameSpaceID != kNameSpaceID_None) { - continue; - } - - // Is this attribute one of the ones we care about? - if (localName == nsGkAtoms::event) - event = aAtts[1]; - else if (localName == nsGkAtoms::modifiers) - modifiers = aAtts[1]; - else if (localName == nsGkAtoms::button) - button = aAtts[1]; - else if (localName == nsGkAtoms::clickcount) - clickcount = aAtts[1]; - else if (localName == nsGkAtoms::keycode) - keycode = aAtts[1]; - else if (localName == nsGkAtoms::key || localName == nsGkAtoms::charcode) - charcode = aAtts[1]; - else if (localName == nsGkAtoms::phase) - phase = aAtts[1]; - else if (localName == nsGkAtoms::command) - command = aAtts[1]; - else if (localName == nsGkAtoms::action) - action = aAtts[1]; - else if (localName == nsGkAtoms::group) - group = aAtts[1]; - else if (localName == nsGkAtoms::preventdefault) - preventdefault = aAtts[1]; - else if (localName == nsGkAtoms::allowuntrusted) - allowuntrusted = aAtts[1]; - } - - if (command && !mIsChromeOrResource) { - // Make sure the XBL doc is chrome or resource if we have a command - // shorthand syntax. - mState = eXBL_Error; - nsContentUtils::ReportToConsole( - nsIScriptError::errorFlag, NS_LITERAL_CSTRING("XBL Content Sink"), - mDocument, nsContentUtils::eXBL_PROPERTIES, "CommandNotInChrome", - nsTArray<nsString>(), nullptr, EmptyString() /* source line */, - aLineNumber); - return; // Don't even make this handler. - } - - // All of our pointers are now filled in. Construct our handler with all of - // these parameters. - nsXBLPrototypeHandler* newHandler; - newHandler = new nsXBLPrototypeHandler( - event, phase, action, command, keycode, charcode, modifiers, button, - clickcount, group, preventdefault, allowuntrusted, mBinding, aLineNumber); - - // Add this handler to our chain of handlers. - if (mHandler) { - // Already have a chain. Just append to the end. - mHandler->SetNextHandler(newHandler); - } else { - // We're the first handler in the chain. - mBinding->SetPrototypeHandlers(newHandler); - } - // Adjust our mHandler pointer to point to the new last handler in the - // chain. - mHandler = newHandler; -} - -void nsXBLContentSink::ConstructImplementation(const char16_t** aAtts) { - mImplementation = nullptr; - mImplMember = nullptr; - mImplField = nullptr; - - if (!mBinding) return; - - const char16_t* name = nullptr; - - RefPtr<nsAtom> prefix, localName; - for (; *aAtts; aAtts += 2) { - int32_t nameSpaceID; - nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix), - getter_AddRefs(localName), &nameSpaceID); - - if (nameSpaceID != kNameSpaceID_None) { - continue; - } - - // Is this attribute one of the ones we care about? - if (localName == nsGkAtoms::name) { - name = aAtts[1]; - } else if (localName == nsGkAtoms::implements) { - // Only allow implementation of interfaces via XBL if the principal of - // our XBL document is the system principal. - if (nsContentUtils::IsSystemPrincipal(mDocument->NodePrincipal())) { - mBinding->ConstructInterfaceTable(nsDependentString(aAtts[1])); - } - } - } - - NS_NewXBLProtoImpl(mBinding, name, &mImplementation); -} - -void nsXBLContentSink::ConstructField(const char16_t** aAtts, - uint32_t aLineNumber) { - const char16_t* name = nullptr; - const char16_t* readonly = nullptr; - - RefPtr<nsAtom> prefix, localName; - for (; *aAtts; aAtts += 2) { - int32_t nameSpaceID; - nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix), - getter_AddRefs(localName), &nameSpaceID); - - if (nameSpaceID != kNameSpaceID_None) { - continue; - } - - // Is this attribute one of the ones we care about? - if (localName == nsGkAtoms::name) { - name = aAtts[1]; - } else if (localName == nsGkAtoms::readonly) { - readonly = aAtts[1]; - } - } - - if (name) { - // All of our pointers are now filled in. Construct our field with all of - // these parameters. - mField = new nsXBLProtoImplField(name, readonly); - mField->SetLineNumber(aLineNumber); - AddField(mField); - } -} - -void nsXBLContentSink::ConstructProperty(const char16_t** aAtts, - uint32_t aLineNumber) { - const char16_t* name = nullptr; - const char16_t* readonly = nullptr; - const char16_t* onget = nullptr; - const char16_t* onset = nullptr; - bool exposeToUntrustedContent = false; - - RefPtr<nsAtom> prefix, localName; - for (; *aAtts; aAtts += 2) { - int32_t nameSpaceID; - nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix), - getter_AddRefs(localName), &nameSpaceID); - - if (nameSpaceID != kNameSpaceID_None) { - continue; - } - - // Is this attribute one of the ones we care about? - if (localName == nsGkAtoms::name) { - name = aAtts[1]; - } else if (localName == nsGkAtoms::readonly) { - readonly = aAtts[1]; - } else if (localName == nsGkAtoms::onget) { - onget = aAtts[1]; - } else if (localName == nsGkAtoms::onset) { - onset = aAtts[1]; - } else if (localName == nsGkAtoms::exposeToUntrustedContent && - nsDependentString(aAtts[1]).EqualsLiteral("true")) { - exposeToUntrustedContent = true; - } - } - - if (name) { - // All of our pointers are now filled in. Construct our property with all of - // these parameters. - mProperty = - new nsXBLProtoImplProperty(name, onget, onset, readonly, aLineNumber); - if (exposeToUntrustedContent) { - mProperty->SetExposeToUntrustedContent(true); - } - AddMember(mProperty); - } -} - -void nsXBLContentSink::ConstructMethod(const char16_t** aAtts) { - mMethod = nullptr; - - const char16_t* name = nullptr; - const char16_t* expose = nullptr; - if (FindValue(aAtts, nsGkAtoms::name, &name)) { - mMethod = new nsXBLProtoImplMethod(name); - if (FindValue(aAtts, nsGkAtoms::exposeToUntrustedContent, &expose) && - nsDependentString(expose).EqualsLiteral("true")) { - mMethod->SetExposeToUntrustedContent(true); - } - } - - if (mMethod) { - AddMember(mMethod); - } -} - -void nsXBLContentSink::ConstructParameter(const char16_t** aAtts) { - if (!mMethod) return; - - const char16_t* name = nullptr; - if (FindValue(aAtts, nsGkAtoms::name, &name)) { - mMethod->AddParameter(nsDependentString(name)); - } -} - -nsresult nsXBLContentSink::CreateElement( - const char16_t** aAtts, uint32_t aAttsCount, - mozilla::dom::NodeInfo* aNodeInfo, uint32_t aLineNumber, - uint32_t aColumnNumber, nsIContent** aResult, bool* aAppendContent, - FromParser aFromParser) { -#ifdef MOZ_XUL - if (!aNodeInfo->NamespaceEquals(kNameSpaceID_XUL)) { -#endif - return nsXMLContentSink::CreateElement(aAtts, aAttsCount, aNodeInfo, - aLineNumber, aColumnNumber, aResult, - aAppendContent, aFromParser); -#ifdef MOZ_XUL - } - - // Note that this needs to match the code in - // nsXBLPrototypeBinding::ReadContentNode. - - *aAppendContent = true; - RefPtr<nsXULPrototypeElement> prototype = - new nsXULPrototypeElement(aNodeInfo); - - AddAttributesToXULPrototype(aAtts, aAttsCount, prototype); - - Element* result; - nsresult rv = nsXULElement::CreateFromPrototype(prototype, mDocument, false, - false, &result); - *aResult = result; - return rv; -#endif -} - -nsresult nsXBLContentSink::AddAttributes(const char16_t** aAtts, - Element* aElement) { - if (aElement->IsXULElement()) - return NS_OK; // Nothing to do, since the proto already has the attrs. - - return nsXMLContentSink::AddAttributes(aAtts, aElement); -} - -#ifdef MOZ_XUL -nsresult nsXBLContentSink::AddAttributesToXULPrototype( - const char16_t** aAtts, uint32_t aAttsCount, - nsXULPrototypeElement* aElement) { - // Add tag attributes to the element - nsresult rv; - - // Create storage for the attributes - nsXULPrototypeAttribute* attrs = nullptr; - if (aAttsCount > 0) { - attrs = aElement->mAttributes.AppendElements(aAttsCount); - } - - // Copy the attributes into the prototype - RefPtr<nsAtom> prefix, localName; - - uint32_t i; - for (i = 0; i < aAttsCount; ++i) { - int32_t nameSpaceID; - nsContentUtils::SplitExpatName(aAtts[i * 2], getter_AddRefs(prefix), - getter_AddRefs(localName), &nameSpaceID); - - if (nameSpaceID == kNameSpaceID_None) { - attrs[i].mName.SetTo(localName); - } else { - RefPtr<NodeInfo> ni; - ni = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID, - nsINode::ATTRIBUTE_NODE); - attrs[i].mName.SetTo(ni); - } - - rv = aElement->SetAttrAt(i, nsDependentString(aAtts[i * 2 + 1]), - mDocumentURI); - NS_ENSURE_SUCCESS(rv, rv); - } - - return NS_OK; -} -#endif
deleted file mode 100644 --- a/dom/xbl/nsXBLContentSink.h +++ /dev/null @@ -1,145 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* 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 nsXBLContentSink_h__ -#define nsXBLContentSink_h__ - -#include "mozilla/Attributes.h" -#include "nsXMLContentSink.h" -#include "nsXBLDocumentInfo.h" -#include "nsXBLPrototypeHandler.h" -#include "nsXBLProtoImpl.h" -#include "nsLayoutCID.h" - -/* - * Enum that describes the primary state of the parsing process - */ -typedef enum { - eXBL_InDocument, /* outside any bindings */ - eXBL_InBindings, /* Inside a <bindings> element */ - eXBL_InBinding, /* Inside a <binding> */ - eXBL_InImplementation, /* Inside a <implementation> */ - eXBL_InHandlers, /* Inside a <handlers> */ - eXBL_Error /* An error has occurred. Suspend binding construction */ -} XBLPrimaryState; - -/* - * Enum that describes our substate (typically when parsing something - * like <handlers> or <implementation>). - */ -typedef enum { - eXBL_None, - eXBL_InHandler, - eXBL_InMethod, - eXBL_InProperty, - eXBL_InField, - eXBL_InBody, - eXBL_InGetter, - eXBL_InSetter, - eXBL_InConstructor, - eXBL_InDestructor -} XBLSecondaryState; - -class nsXULPrototypeElement; -class nsXBLProtoImplMember; -class nsXBLProtoImplProperty; -class nsXBLProtoImplMethod; -class nsXBLProtoImplField; -class nsXBLPrototypeBinding; - -// The XBL content sink overrides the XML content sink to -// builds its own lightweight data structures for the <resources>, -// <handlers>, <implementation>, and - -class nsXBLContentSink : public nsXMLContentSink { - public: - nsXBLContentSink(); - ~nsXBLContentSink(); - - nsresult Init(mozilla::dom::Document* aDoc, nsIURI* aURL, - nsISupports* aContainer); - - // nsIContentSink overrides - NS_IMETHOD HandleStartElement(const char16_t* aName, const char16_t** aAtts, - uint32_t aAttsCount, uint32_t aLineNumber, - uint32_t aColumnNumber) override; - - NS_IMETHOD HandleEndElement(const char16_t* aName) override; - - NS_IMETHOD HandleCDataSection(const char16_t* aData, - uint32_t aLength) override; - - protected: - // nsXMLContentSink overrides - virtual void MaybeStartLayout(bool aIgnorePendingSheets) override; - - bool OnOpenContainer(const char16_t** aAtts, uint32_t aAttsCount, - int32_t aNameSpaceID, nsAtom* aTagName, - uint32_t aLineNumber) override; - - bool NotifyForDocElement() override { return false; } - - nsresult CreateElement(const char16_t** aAtts, uint32_t aAttsCount, - mozilla::dom::NodeInfo* aNodeInfo, - uint32_t aLineNumber, uint32_t aColumnNumber, - nsIContent** aResult, bool* aAppendContent, - mozilla::dom::FromParser aFromParser) override; - - nsresult AddAttributes(const char16_t** aAtts, - mozilla::dom::Element* aElement) override; - -#ifdef MOZ_XUL - nsresult AddAttributesToXULPrototype(const char16_t** aAtts, - uint32_t aAttsCount, - nsXULPrototypeElement* aElement); -#endif - - // Our own helpers for constructing XBL prototype objects. - nsresult ConstructBinding(uint32_t aLineNumber); - void ConstructHandler(const char16_t** aAtts, uint32_t aLineNumber); - void ConstructImplementation(const char16_t** aAtts); - void ConstructProperty(const char16_t** aAtts, uint32_t aLineNumber); - void ConstructMethod(const char16_t** aAtts); - void ConstructParameter(const char16_t** aAtts); - void ConstructField(const char16_t** aAtts, uint32_t aLineNumber); - - // nsXMLContentSink overrides - nsresult FlushText(bool aReleaseTextNode = true) override; - - // nsIExpatSink overrides - NS_IMETHOD ReportError(const char16_t* aErrorText, - const char16_t* aSourceText, nsIScriptError* aError, - bool* _retval) override; - - protected: - nsresult ReportUnexpectedElement(nsAtom* aElementName, uint32_t aLineNumber); - - void AddMember(nsXBLProtoImplMember* aMember); - void AddField(nsXBLProtoImplField* aField); - - XBLPrimaryState mState; - XBLSecondaryState mSecondaryState; - nsXBLDocumentInfo* mDocInfo; - bool mIsChromeOrResource; // For bug #45989 - bool mFoundFirstBinding; - - nsString mCurrentBindingID; - - nsXBLPrototypeBinding* mBinding; - nsXBLPrototypeHandler* - mHandler; // current handler, owned by its PrototypeBinding - nsXBLProtoImpl* mImplementation; - nsXBLProtoImplMember* mImplMember; - nsXBLProtoImplField* mImplField; - nsXBLProtoImplProperty* mProperty; - nsXBLProtoImplMethod* mMethod; - nsXBLProtoImplField* mField; -}; - -nsresult NS_NewXBLContentSink(nsIXMLContentSink** aResult, - mozilla::dom::Document* aDoc, nsIURI* aURL, - nsISupports* aContainer); -#endif // nsXBLContentSink_h__
deleted file mode 100644 --- a/dom/xbl/nsXBLDocumentInfo.cpp +++ /dev/null @@ -1,311 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* 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/. */ - -#include "mozilla/DebugOnly.h" - -#include "nsXBLDocumentInfo.h" -#include "mozilla/dom/Document.h" -#include "nsXBLPrototypeBinding.h" -#include "nsIScriptObjectPrincipal.h" -#include "nsIScriptContext.h" -#include "jsapi.h" -#include "jsfriendapi.h" -#include "nsIURI.h" -#include "nsIConsoleService.h" -#include "nsIScriptError.h" -#include "nsIChromeRegistry.h" -#include "nsIPrincipal.h" -#include "nsJSPrincipals.h" -#include "nsIScriptSecurityManager.h" -#include "nsContentUtils.h" -#include "nsDOMJSUtils.h" -#include "nsWindowSizes.h" -#include "mozilla/Services.h" -#include "xpcpublic.h" -#include "mozilla/scache/StartupCache.h" -#include "mozilla/scache/StartupCacheUtils.h" -#include "nsCCUncollectableMarker.h" -#include "mozilla/dom/BindingUtils.h" -#include "mozilla/dom/URL.h" - -using namespace mozilla; -using namespace mozilla::scache; -using namespace mozilla::dom; - -static const char kXBLCachePrefix[] = "xblcache"; - -/* Implementation file */ -NS_IMPL_CYCLE_COLLECTION_CLASS(nsXBLDocumentInfo) - -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXBLDocumentInfo) - if (tmp->mBindingTable) { - for (auto iter = tmp->mBindingTable->ConstIter(); !iter.Done(); - iter.Next()) { - iter.UserData()->Unlink(); - } - } - NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument) -NS_IMPL_CYCLE_COLLECTION_UNLINK_END -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXBLDocumentInfo) - if (tmp->mDocument && nsCCUncollectableMarker::InGeneration( - cb, tmp->mDocument->GetMarkedCCGeneration())) { - return NS_SUCCESS_INTERRUPTED_TRAVERSE; - } - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument) - if (tmp->mBindingTable) { - for (auto iter = tmp->mBindingTable->ConstIter(); !iter.Done(); - iter.Next()) { - iter.UserData()->Traverse(cb); - } - } -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END -NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsXBLDocumentInfo) - if (tmp->mBindingTable) { - for (auto iter = tmp->mBindingTable->ConstIter(); !iter.Done(); - iter.Next()) { - iter.UserData()->Trace(aCallbacks, aClosure); - } - } -NS_IMPL_CYCLE_COLLECTION_TRACE_END - -static void UnmarkXBLJSObject(JS::GCCellPtr aPtr, const char* aName, - void* aClosure) { - JS::ExposeObjectToActiveJS(&aPtr.as<JSObject>()); -} - -void nsXBLDocumentInfo::MarkInCCGeneration(uint32_t aGeneration) { - if (mDocument) { - mDocument->MarkUncollectableForCCGeneration(aGeneration); - } - // Unmark any JS we hold - if (mBindingTable) { - for (auto iter = mBindingTable->Iter(); !iter.Done(); iter.Next()) { - iter.UserData()->Trace(TraceCallbackFunc(UnmarkXBLJSObject), nullptr); - } - } -} - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXBLDocumentInfo) - NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) - NS_INTERFACE_MAP_ENTRY(nsISupports) -NS_INTERFACE_MAP_END - -NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXBLDocumentInfo) -NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXBLDocumentInfo) - -nsXBLDocumentInfo::nsXBLDocumentInfo(Document* aDocument) - : mDocument(aDocument), - mScriptAccess(true), - mIsChrome(false), - mFirstBinding(nullptr) { - nsIURI* uri = aDocument->GetDocumentURI(); - if (IsChromeURI(uri)) { - // Cache whether or not this chrome XBL can execute scripts. - nsCOMPtr<nsIXULChromeRegistry> reg = - mozilla::services::GetXULChromeRegistryService(); - if (reg) { - bool allow = true; - reg->AllowScriptsForPackage(uri, &allow); - mScriptAccess = allow; - } - mIsChrome = true; - } else { - // If this binding isn't running with system principal, then it's running - // from a remote-XUL whitelisted domain. This is already a not-really- - // supported configuration (among other things, we don't use XBL scopes in - // that configuration for compatibility reasons). But we should still at - // least make an effort to prevent binding code from running if content - // script is disabled or if the source domain is blacklisted (since the - // source domain for remote XBL must always be the same as the source domain - // of the bound content). - // - // If we just ask the binding document if script is enabled, it will - // discover that it has no inner window, and return false. So instead, we - // short-circuit the normal compartment-managed script-disabling machinery, - // and query the policy for the URI directly. - bool allow; - nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); - nsresult rv = ssm->PolicyAllowsScript(uri, &allow); - mScriptAccess = NS_SUCCEEDED(rv) && allow; - } -} - -nsXBLDocumentInfo::~nsXBLDocumentInfo() { mozilla::DropJSObjects(this); } - -nsXBLPrototypeBinding* nsXBLDocumentInfo::GetPrototypeBinding( - const nsACString& aRef) { - if (!mBindingTable) return nullptr; - - if (aRef.IsEmpty()) { - // Return our first binding - return mFirstBinding; - } - - return mBindingTable->Get(aRef); -} - -nsresult nsXBLDocumentInfo::SetPrototypeBinding( - const nsACString& aRef, nsXBLPrototypeBinding* aBinding) { - if (!mBindingTable) { - mBindingTable = - new nsClassHashtable<nsCStringHashKey, nsXBLPrototypeBinding>(); - mozilla::HoldJSObjects(this); - } - - NS_ENSURE_STATE(!mBindingTable->Get(aRef)); - mBindingTable->Put(aRef, aBinding); - - return NS_OK; -} - -void nsXBLDocumentInfo::RemovePrototypeBinding(const nsACString& aRef) { - if (mBindingTable) { - nsAutoPtr<nsXBLPrototypeBinding> bindingToRemove; - mBindingTable->Remove(aRef, &bindingToRemove); - - // We do not want to destroy the binding, so just forget it. - bindingToRemove.forget(); - } -} - -// static -nsresult nsXBLDocumentInfo::ReadPrototypeBindings(nsIURI* aURI, - nsXBLDocumentInfo** aDocInfo, - Document* aBoundDocument) { - *aDocInfo = nullptr; - - nsAutoCString spec(kXBLCachePrefix); - nsresult rv = PathifyURI(aURI, spec); - NS_ENSURE_SUCCESS(rv, rv); - - StartupCache* startupCache = StartupCache::GetSingleton(); - if (!startupCache) { - return NS_ERROR_FAILURE; - } - - const char* buf; - uint32_t len; - rv = startupCache->GetBuffer(spec.get(), &buf, &len); - // GetBuffer will fail if the binding is not in the cache. - if (NS_FAILED(rv)) return rv; - - nsCOMPtr<nsIObjectInputStream> stream; - rv = NewObjectInputStreamFromBuffer(buf, len, getter_AddRefs(stream)); - NS_ENSURE_SUCCESS(rv, rv); - - // The file compatibility.ini stores the build id. This is checked in - // nsAppRunner.cpp and will delete the cache if a different build is - // present. However, we check that the version matches here to be safe. - uint32_t version; - rv = stream->Read32(&version); - NS_ENSURE_SUCCESS(rv, rv); - if (version != XBLBinding_Serialize_Version) { - // The version that exists is different than expected, likely created with a - // different build, so invalidate the cache. - startupCache->InvalidateCache(); - return NS_ERROR_NOT_AVAILABLE; - } - - nsCOMPtr<nsIPrincipal> principal; - nsContentUtils::GetSecurityManager()->GetSystemPrincipal( - getter_AddRefs(principal)); - - nsCOMPtr<Document> doc; - rv = NS_NewXBLDocument(getter_AddRefs(doc), aURI, nullptr, principal); - NS_ENSURE_SUCCESS(rv, rv); - - RefPtr<nsXBLDocumentInfo> docInfo = new nsXBLDocumentInfo(doc); - - while (1) { - uint8_t flags; - nsresult rv = stream->Read8(&flags); - NS_ENSURE_SUCCESS(rv, rv); - if (flags == XBLBinding_Serialize_NoMoreBindings) break; - - rv = nsXBLPrototypeBinding::ReadNewBinding(stream, docInfo, doc, flags); - if (NS_FAILED(rv)) { - return rv; - } - } - - docInfo.forget(aDocInfo); - return NS_OK; -} - -nsresult nsXBLDocumentInfo::WritePrototypeBindings() { - // Only write out bindings with the system principal - if (!nsContentUtils::IsSystemPrincipal(mDocument->NodePrincipal())) - return NS_OK; - - nsAutoCString spec(kXBLCachePrefix); - nsresult rv = PathifyURI(DocumentURI(), spec); - NS_ENSURE_SUCCESS(rv, rv); - - StartupCache* startupCache = StartupCache::GetSingleton(); - if (!startupCache) { - return rv; - } - - nsCOMPtr<nsIObjectOutputStream> stream; - nsCOMPtr<nsIStorageStream> storageStream; - rv = NewObjectOutputWrappedStorageStream(getter_AddRefs(stream), - getter_AddRefs(storageStream), true); - NS_ENSURE_SUCCESS(rv, rv); - - rv = stream->Write32(XBLBinding_Serialize_Version); - NS_ENSURE_SUCCESS(rv, rv); - - if (mBindingTable) { - for (auto iter = mBindingTable->Iter(); !iter.Done(); iter.Next()) { - iter.UserData()->Write(stream); - } - } - - // write a end marker at the end - rv = stream->Write8(XBLBinding_Serialize_NoMoreBindings); - NS_ENSURE_SUCCESS(rv, rv); - - stream->Close(); - NS_ENSURE_SUCCESS(rv, rv); - - uint32_t len; - UniquePtr<char[]> buf; - rv = NewBufferFromStorageStream(storageStream, &buf, &len); - NS_ENSURE_SUCCESS(rv, rv); - - return startupCache->PutBuffer(spec.get(), std::move(buf), len); -} - -void nsXBLDocumentInfo::SetFirstPrototypeBinding( - nsXBLPrototypeBinding* aBinding) { - mFirstBinding = aBinding; -} - -#ifdef DEBUG -void AssertInCompilationScope() { - AutoJSContext cx; - MOZ_ASSERT(xpc::CompilationScope() == JS::CurrentGlobalOrNull(cx)); -} -#endif - -size_t nsXBLDocumentInfo::SizeOfIncludingThis( - MallocSizeOf aMallocSizeOf) const { - size_t n = aMallocSizeOf(this); - if (mDocument) { - SizeOfState state(aMallocSizeOf); - nsWindowSizes windowSizes(state); - mDocument->DocAddSizeOfIncludingThis(windowSizes); - n += windowSizes.getTotalSize(); - } - if (mBindingTable) { - n += mBindingTable->ShallowSizeOfIncludingThis(aMallocSizeOf); - for (auto iter = mBindingTable->Iter(); !iter.Done(); iter.Next()) { - nsXBLPrototypeBinding* binding = iter.UserData(); - n += binding->SizeOfIncludingThis(aMallocSizeOf); - } - } - return n; -}
deleted file mode 100644 --- a/dom/xbl/nsXBLDocumentInfo.h +++ /dev/null @@ -1,75 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* 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 nsXBLDocumentInfo_h__ -#define nsXBLDocumentInfo_h__ - -#include "mozilla/Attributes.h" -#include "mozilla/MemoryReporting.h" -#include "nsCOMPtr.h" -#include "nsAutoPtr.h" -#include "nsWeakReference.h" -#include "mozilla/dom/Document.h" -#include "nsCycleCollectionParticipant.h" - -class nsXBLPrototypeBinding; - -class nsXBLDocumentInfo final : public nsSupportsWeakReference { - public: - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - - explicit nsXBLDocumentInfo(mozilla::dom::Document* aDocument); - - mozilla::dom::Document* GetDocument() const { return mDocument; } - - bool GetScriptAccess() const { return mScriptAccess; } - - nsIURI* DocumentURI() { return mDocument->GetDocumentURI(); } - - nsXBLPrototypeBinding* GetPrototypeBinding(const nsACString& aRef); - nsresult SetPrototypeBinding(const nsACString& aRef, - nsXBLPrototypeBinding* aBinding); - - // This removes the binding without deleting it - void RemovePrototypeBinding(const nsACString& aRef); - - nsresult WritePrototypeBindings(); - - void SetFirstPrototypeBinding(nsXBLPrototypeBinding* aBinding); - - bool IsChrome() { return mIsChrome; } - - void MarkInCCGeneration(uint32_t aGeneration); - - static nsresult ReadPrototypeBindings(nsIURI* aURI, - nsXBLDocumentInfo** aDocInfo, - mozilla::dom::Document* aBoundDocument); - - size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; - - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsXBLDocumentInfo) - - private: - virtual ~nsXBLDocumentInfo(); - - RefPtr<mozilla::dom::Document> mDocument; - bool mScriptAccess; - bool mIsChrome; - // the binding table owns each nsXBLPrototypeBinding - nsAutoPtr<nsClassHashtable<nsCStringHashKey, nsXBLPrototypeBinding>> - mBindingTable; - - // non-owning pointer to the first binding in the table - nsXBLPrototypeBinding* mFirstBinding; -}; - -#ifdef DEBUG -void AssertInCompilationScope(); -#else -inline void AssertInCompilationScope() {} -#endif - -#endif
deleted file mode 100644 --- a/dom/xbl/nsXBLEventHandler.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* 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/. */ - -#include "nsCOMPtr.h" -#include "nsAtom.h" -#include "nsIDOMEventListener.h" -#include "nsXBLPrototypeHandler.h" -#include "nsContentUtils.h" -#include "mozilla/dom/Event.h" // for Event -#include "mozilla/dom/EventBinding.h" // for Event -#include "mozilla/dom/EventTarget.h" -#include "mozilla/dom/KeyboardEvent.h" -#include "mozilla/TextEvents.h" - -using namespace mozilla; -using namespace mozilla::dom; - -nsXBLEventHandler::nsXBLEventHandler(nsXBLPrototypeHandler* aHandler) - : mProtoHandler(aHandler) {} - -nsXBLEventHandler::~nsXBLEventHandler() {} - -NS_IMPL_ISUPPORTS(nsXBLEventHandler, nsIDOMEventListener) - -NS_IMETHODIMP -nsXBLEventHandler::HandleEvent(Event* aEvent) { - if (!mProtoHandler) return NS_ERROR_FAILURE; - - uint8_t phase = mProtoHandler->GetPhase(); - if (phase == NS_PHASE_TARGET) { - if (aEvent->EventPhase() != Event_Binding::AT_TARGET) { - return NS_OK; - } - } - - if (!EventMatched(aEvent)) return NS_OK; -