Merge mozilla-central to mozilla-inbound

This commit is contained in:
Carsten "Tomcat" Book 2017-08-16 12:50:39 +02:00
commit e7c657e009
244 changed files with 5331 additions and 3211 deletions

View File

@ -31,7 +31,7 @@ function getWindows() {
* @return A generator that yields XUL windows exposing the
* nsIDOMWindow interface.
*/
function windowIterator() {
function* windowIterator() {
// Bug 752631: We only pass already loaded window in order to avoid
// breaking XUL windows DOM. DOM is broken when some JS code try
// to access DOM during "uninitialized" state of the related document.
@ -48,7 +48,7 @@ exports.windowIterator = windowIterator;
* A generator that yields browser windows exposing the `nsIDOMWindow`
* interface.
*/
function browserWindowIterator() {
function* browserWindowIterator() {
for (let window of windowIterator()) {
if (isBrowser(window))
yield window;

View File

@ -54,7 +54,7 @@ function clear(target) {
}
exports.clear = clear;
function iterator(target) {
function* iterator(target) {
let refs = getRefsFor(target);
for (let ref of refs) {
@ -72,4 +72,4 @@ function iterator(target) {
refs.delete(ref);
}
}
exports.iterator = iterator;
exports[Symbol.iterator] = iterator;

View File

@ -57,7 +57,7 @@ function Collection(array) {
* Provides iteration over the collection. Items are yielded in the order
* they were added.
*/
this.__iterator__ = function Collection___iterator__() {
this[Symbol.iterator] = function* Collection___iterator__() {
let items = array.slice();
for (let i = 0; i < items.length; i++)
yield items[i];

View File

@ -37,19 +37,6 @@ const listOptions = {
toString: function toString() {
return 'List(' + listNS(this).keyValueMap + ')';
},
/**
* Custom iterator providing `List`s enumeration behavior.
* We cant reuse `_iterator` that is defined by `Iterable` since it provides
* iteration in an arbitrary order.
* @see https://developer.mozilla.org/en/JavaScript/Reference/Statements/for...in
* @param {Boolean} onKeys
*/
__iterator__: function __iterator__(onKeys, onKeyValue) {
let array = listNS(this).keyValueMap.slice(0),
i = -1;
for (let element of array)
yield onKeyValue ? [++i, element] : onKeys ? ++i : element;
},
};
listOptions[Symbol.iterator] = function iterator() {
return listNS(this).keyValueMap.slice(0)[Symbol.iterator]();

View File

@ -134,8 +134,12 @@
el.remove();
}
// Set sitename
document.getElementById(error + "_sitename").textContent = getHostString();
// Set sitename if necessary.
let sitenameElem = document.getElementById(error + "_sitename");
if (sitenameElem) {
sitenameElem.textContent = getHostString();
}
document.title = document.getElementById("errorTitleText_" + error)
.innerHTML;

View File

@ -90,8 +90,7 @@ var gSync = {
},
init() {
// Bail out if we're already initialized or for pop-up windows.
if (this._initialized || !window.toolbar.visible) {
if (this._initialized) {
return;
}

View File

@ -1088,14 +1088,6 @@ function _loadURIWithFlags(browser, uri, params) {
}
let mustChangeProcess = requiredRemoteType != currentRemoteType;
let newFrameloader = false;
if (browser.getAttribute("isPreloadBrowser") == "true" && uri != "about:newtab") {
// Leaving about:newtab from a used to be preloaded browser should run the process
// selecting algorithm again.
mustChangeProcess = true;
newFrameloader = true;
browser.removeAttribute("isPreloadBrowser");
}
// !requiredRemoteType means we're loading in the parent/this process.
if (!requiredRemoteType) {
@ -1130,8 +1122,7 @@ function _loadURIWithFlags(browser, uri, params) {
referrer: referrer ? referrer.spec : null,
referrerPolicy,
remoteType: requiredRemoteType,
postData,
newFrameloader,
postData
}
if (params.userContextId) {
@ -1176,11 +1167,6 @@ function LoadInOtherProcess(browser, loadOptions, historyIndex = -1) {
// Called when a docshell has attempted to load a page in an incorrect process.
// This function is responsible for loading the page in the correct process.
function RedirectLoad({ target: browser, data }) {
if (browser.getAttribute("isPreloadBrowser") == "true") {
browser.removeAttribute("isPreloadBrowser");
data.loadOptions.newFrameloader = true;
}
if (data.loadOptions.reloadInFreshProcess) {
// Convert the fresh process load option into a large allocation remote type
// to use common processing from this point.
@ -3207,6 +3193,10 @@ var BrowserOnClick = {
title = gNavigatorBundle.getString("safebrowsing.reportedUnwantedSite");
// There is no button for reporting errors since Google doesn't currently
// provide a URL endpoint for these reports.
} else if (reason === "harmful") {
title = gNavigatorBundle.getString("safebrowsing.reportedHarmfulSite");
// There is no button for reporting errors since Google doesn't currently
// provide a URL endpoint for these reports.
}
let notificationBox = gBrowser.getNotificationBox();

View File

@ -2118,10 +2118,6 @@
b.setAttribute("autocompletepopup", this.getAttribute("autocompletepopup"));
}
if (aParams.isPreloadBrowser) {
b.setAttribute("isPreloadBrowser", "true");
}
if (this.hasAttribute("selectmenulist"))
b.setAttribute("selectmenulist", this.getAttribute("selectmenulist"));

View File

@ -131,8 +131,6 @@ skip-if = true # browser_bug321000.js is disabled because newline handling is sh
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
[browser_bug419612.js]
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
[browser_bug422590.js]
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
[browser_bug423833.js]
skip-if = true # bug 428712
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.

View File

@ -1,59 +0,0 @@
function test() {
waitForExplicitFinish();
// test a normal browser window
var newWin = openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no", "about:blank");
ok(newWin, "got new normal window");
whenDelayedStartupFinished(newWin, function() {
testCustomize(newWin, function() {
newWin.close();
testChromeless();
});
});
}
function testChromeless() {
// test a chromeless window
var newWin = openDialog(getBrowserURL(), "_blank",
"chrome,dialog=no,location=yes,toolbar=no", "about:blank");
ok(newWin, "got new window");
whenDelayedStartupFinished(newWin, function() {
// Check that the search bar is hidden
var searchBar = newWin.BrowserSearch.searchBar;
ok(searchBar, "got search bar");
var searchBarBO = searchBar.boxObject;
is(searchBarBO.width, 0, "search bar hidden");
is(searchBarBO.height, 0, "search bar hidden");
testCustomize(newWin, function() {
newWin.close();
finish();
});
});
}
function testCustomize(aWindow, aCallback) {
var fileMenu = aWindow.document.getElementById("file-menu");
ok(fileMenu, "got file menu");
is(fileMenu.disabled, false, "file menu initially enabled");
openToolbarCustomizationUI(function() {
// Can't use the property, since the binding may have since been removed
// if the element is hidden (see bug 422590)
is(fileMenu.getAttribute("disabled"), "true",
"file menu is disabled during toolbar customization");
closeToolbarCustomizationUI(onClose, aWindow);
}, aWindow);
function onClose() {
is(fileMenu.getAttribute("disabled"), "false",
"file menu is enabled after toolbar customization");
if (aCallback)
aCallback();
}
}

View File

@ -20,13 +20,11 @@ var tests = [
location: "http://test1.example.org/",
effectiveHost: "test1.example.org"
},
/* This part is perma-crashing, see: Bug 1315092
{
name: "view-source",
location: "view-source:http://example.com/",
effectiveHost: null
},
*/
{
name: "normal HTTPS",
location: "https://example.com/",

View File

@ -6,7 +6,7 @@
*/
add_task(async function() {
let input = "i-definitely-dont-exist.example.com";
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank", false);
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:newtab", false);
// NB: CPOW usage because new tab pages can be preloaded, in which case no
// load events fire.
await BrowserTestUtils.waitForCondition(() => !tab.linkedBrowser.contentDocument.hidden)
@ -29,7 +29,7 @@ add_task(async function() {
add_task(async function() {
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 tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:newtab", false);
// NB: CPOW usage because new tab pages can be preloaded, in which case no
// load events fire.
await BrowserTestUtils.waitForCondition(() => !tab.linkedBrowser.contentDocument.hidden)

View File

@ -203,6 +203,21 @@ CustomizeMode.prototype = {
},
enter() {
if (!this.window.toolbar.visible) {
let w = this.window.getTopWin(true);
if (w) {
w.gCustomizeMode.enter();
return;
}
let obs = () => {
Services.obs.removeObserver(obs, "browser-delayed-startup-finished");
w = this.window.getTopWin(true);
w.gCustomizeMode.enter();
};
Services.obs.addObserver(obs, "browser-delayed-startup-finished");
this.window.openUILinkIn("about:newtab", "window");
return;
}
this._wantToBeInCustomizeMode = true;
if (this._customizing || this._handler.isEnteringCustomizeMode) {

View File

@ -156,5 +156,6 @@ tags = fullscreen
[browser_editcontrols_update.js]
subsuite = clipboard
[browser_customization_context_menus.js]
[browser_open_from_popup.js]
[browser_sidebar_toggle.js]
[browser_remote_tabs_button.js]

View File

@ -0,0 +1,19 @@
"use strict";
/**
* Check that opening customize mode in a popup opens it in the main window.
*/
add_task(async function open_customize_mode_from_popup() {
let promiseWindow = BrowserTestUtils.waitForNewWindow(true);
ContentTask.spawn(gBrowser.selectedBrowser, null, function() {
content.window.open("about:blank", "_blank", "height=300,toolbar=no");
});
let win = await promiseWindow;
let customizePromise = BrowserTestUtils.waitForEvent(gNavToolbox, "customizationready");
win.gCustomizeMode.enter();
await customizePromise;
ok(document.documentElement.hasAttribute("customizing"),
"Should have opened customize mode in the parent window");
await endCustomizing();
await BrowserTestUtils.closeWindow(win);
});

View File

@ -349,7 +349,7 @@
</menulist>
</html:td>
</html:tr>
<html:tr>
<html:tr class="tableGroup">
<html:td class="label-cell">
<label accesskey="&homepage2.accesskey;"
control="browserHomePage">&homepage2.label;</label>
@ -365,7 +365,7 @@
preference="browser.startup.homepage"/>
</html:td>
</html:tr>
<html:tr>
<html:tr class="tableSubGroup">
<html:td class="label-cell" />
<html:td class="content-cell homepage-buttons">
<button id="useCurrent"
@ -756,7 +756,6 @@
<!-- Update -->
<groupbox id="updateApp" data-category="paneGeneral" hidden="true">
<label>&updateApplicationDescription.label;</label>
<separator/>
<hbox align="start">
<vbox flex="1">
<description>
@ -872,7 +871,6 @@
</vbox>
#endif
<separator/>
#ifdef MOZ_UPDATER
<description>&updateApplication.description;</description>
<radiogroup id="updateRadioGroup">

View File

@ -493,6 +493,7 @@
<hbox>
<button id="trackingProtectionExceptions"
class="accessory-button"
flex="1"
hidden="true"
label="&trackingProtectionExceptions.label;"
accesskey="&trackingProtectionExceptions.accesskey;"
@ -506,6 +507,7 @@
<hbox>
<button id="changeBlockList"
class="accessory-button"
flex="1"
label="&changeBlockList2.label;"
accesskey="&changeBlockList2.accesskey;"
preference="pref.privacy.disable_button.change_blocklist"

View File

@ -28,8 +28,8 @@
<!-- Default Search Engine -->
<groupbox id="defaultEngineGroup" data-category="paneSearch">
<caption label="&defaultSearchEngine.label;"/>
<label>&chooseYourDefaultSearchEngine2.label;</label>
<caption><label>&defaultSearchEngine.label;</label></caption>
<description>&chooseYourDefaultSearchEngine2.label;</description>
<hbox>
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
<hbox>
@ -54,8 +54,8 @@
</groupbox>
<groupbox id="oneClickSearchProvidersGroup" data-category="paneSearch">
<caption label="&oneClickSearchEngines.label;"/>
<label>&chooseWhichOneToDisplay2.label;</label>
<caption><label>&oneClickSearchEngines.label;</label></caption>
<description>&chooseWhichOneToDisplay2.label;</description>
<tree id="engineList" flex="1" rows="8" hidecolumnpicker="true" editable="true"
seltype="single">
@ -81,9 +81,6 @@
disabled="true"
/>
</hbox>
<separator class="thin"/>
<hbox id="addEnginesBox" pack="start">
<label id="addEngines" class="text-link">&findMoreSearchEngines.label;</label>
</hbox>

View File

@ -5,7 +5,7 @@
<stringbundle id="searchResultBundle" src="chrome://browser/locale/preferences/preferences.properties"/>
<hbox id="header-searchResults"
class="header"
class="subcategory"
hidden="true"
data-category="paneSearchResults">
<label class="header-name" flex="1">&paneSearchResults.title;</label>

View File

@ -202,20 +202,18 @@
</label>
</caption>
<hbox id="fxaDeviceName">
<textbox id="fxaSyncComputerName" disabled="true"/>
<hbox>
<button id="fxaChangeDeviceName"
label="&changeSyncDeviceName2.label;"
accesskey="&changeSyncDeviceName2.accesskey;"/>
<button id="fxaCancelChangeDeviceName"
label="&cancelChangeSyncDeviceName.label;"
accesskey="&cancelChangeSyncDeviceName.accesskey;"
hidden="true"/>
<button id="fxaSaveChangeDeviceName"
label="&saveChangeSyncDeviceName.label;"
accesskey="&saveChangeSyncDeviceName.accesskey;"
hidden="true"/>
</hbox>
<textbox id="fxaSyncComputerName" flex="1" disabled="true"/>
<button id="fxaChangeDeviceName"
label="&changeSyncDeviceName2.label;"
accesskey="&changeSyncDeviceName2.accesskey;"/>
<button id="fxaCancelChangeDeviceName"
label="&cancelChangeSyncDeviceName.label;"
accesskey="&cancelChangeSyncDeviceName.accesskey;"
hidden="true"/>
<button id="fxaSaveChangeDeviceName"
label="&saveChangeSyncDeviceName.label;"
accesskey="&saveChangeSyncDeviceName.accesskey;"
hidden="true"/>
</hbox>
</groupbox>
<label class="fxaMobilePromo">

View File

@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
.website-name {
padding-inline-start: 7px;
-moz-box-align: center;
}

View File

@ -62,8 +62,10 @@
display: inline-block;
offset-inline-start: 39px;
border-radius: 22px;
padding: 5px 8px;
width: 110px;
padding: 5px 12px;
min-width: 100px;
max-width: 140px;
white-space: pre-line;
margin-inline-start: 3px;
margin-top: -5px;
}
@ -251,6 +253,8 @@
line-height: 22px;
padding-inline-start: 40px;
padding-inline-end: 28px;
max-height: 360px;
overflow: auto;
}
.onboarding-tour-description > h1 {

View File

@ -492,12 +492,6 @@ class Onboarding {
this.gotoPage(tourId);
this._removeTourFromNotificationQueue(tourId);
break;
// These tours are tagged completed instantly upon showing.
case "onboarding-tour-default-browser":
case "onboarding-tour-sync":
case "onboarding-tour-performance":
this.setToursCompleted([ evt.target.id ]);
break;
}
let classList = evt.target.classList;
if (classList.contains("onboarding-tour-item")) {
@ -557,6 +551,15 @@ class Onboarding {
li.classList.remove("onboarding-active");
}
}
switch (tourId) {
// These tours should tagged completed instantly upon showing.
case "onboarding-tour-default-browser":
case "onboarding-tour-sync":
case "onboarding-tour-performance":
this.setToursCompleted([tourId]);
break;
}
}
isTourCompleted(tourId) {
@ -827,7 +830,7 @@ class Onboarding {
_renderOverlayButton() {
let button = this._window.document.createElement("button");
let tooltipStringId = this._tourType === "new" ?
"onboarding.overlay-icon-tooltip" : "onboarding.overlay-icon-tooltip-updated";
"onboarding.overlay-icon-tooltip2" : "onboarding.overlay-icon-tooltip-updated2";
let tooltip = this._bundle.formatStringFromName(tooltipStringId, [BRAND_SHORT_NAME], 1);
button.setAttribute("aria-label", tooltip);
button.id = "onboarding-overlay-button";

View File

@ -8,10 +8,15 @@ onboarding.hidden-checkbox-label-text=Mark all as complete, and hide the tour
onboarding.button.learnMore=Learn More
# LOCALIZATION NOTE(onboarding.notification-icon-tool-tip): This string will be used to show the tooltip alongside the notification icon in the notification bar. %S is brandShortName.
onboarding.notification-icon-tool-tip=New to %S?
# LOCALIZATION NOTE(onboarding.overlay-icon-tooltip): This string will be used to show the tooltip alongside the notification icon in the overlay tour. %S is brandShortName.
onboarding.overlay-icon-tooltip=New to %S? Lets get started.
# LOCALIZATION NOTE(onboarding.overlay-icon-tooltip-updated): %S is brandShortName.
onboarding.overlay-icon-tooltip-updated=%S is all new. See what you can do!
# LOCALIZATION NOTE(onboarding.overlay-icon-tooltip2): This string will be used
# to show the tooltip alongside the notification icon in the overlay tour. %S is
# brandShortName. The tooltip is designed to show in two lines. Please use \n to
# do appropriate line breaking.
onboarding.overlay-icon-tooltip2=New to %S?\nLets get started.
# LOCALIZATION NOTE(onboarding.overlay-icon-tooltip-updated2): %S is
# brandShortName. The tooltip is designed to show in two lines. Please use \n to
# do appropriate line breaking.
onboarding.overlay-icon-tooltip-updated2=%S is all new.\nSee what you can do!
# LOCALIZATION NOTE(onboarding.overlay-close-button-tooltip): The overlay close button is an icon button. This tooltip would be shown when mousing hovering on the button.
onboarding.overlay-close-button-tooltip=Close
onboarding.notification-icon-tooltip-updated=See whats new!

View File

@ -23,7 +23,7 @@ panelmultiview[mainViewId=PanelUI-pocketView] > .panel-viewcontainer > .panel-vi
}
#pocket-button-box[open="true"] > #pocket-button {
fill: rgb(213,32,20);
fill: #ef4056;
fill-opacity: 1;
}
@ -99,7 +99,7 @@ panelmultiview[mainViewId=PanelUI-pocketView] > .panel-viewcontainer > .panel-vi
animation-timing-function: steps(12);
animation-duration: 200ms;
background-image: url("chrome://pocket-shared/skin/pocket-animation.svg");
fill: rgb(213,32,20);
fill: #ef4056;
-moz-context-properties: fill;
width: 260px;
}
@ -122,11 +122,11 @@ panelmultiview[mainViewId=PanelUI-pocketView] > .panel-viewcontainer > .panel-vi
fill: inherit;
}
50% {
fill: rgb(213,32,20);
fill: #ef4056;
}
to {
transform: translateX(-1056px);
fill: rgb(213,32,20);
fill: #ef4056;
}
}
@ -139,11 +139,11 @@ panelmultiview[mainViewId=PanelUI-pocketView] > .panel-viewcontainer > .panel-vi
fill: inherit;
}
50% {
fill: rgb(213,32,20);
fill: #ef4056;
}
to {
transform: scaleX(-1) translateX(-1056px);
fill: rgb(213,32,20);
fill: #ef4056;
}
}
@ -162,7 +162,7 @@ panelmultiview[mainViewId=PanelUI-pocketView] > .panel-viewcontainer > .panel-vi
then no transition will occur and thus no transitionend event. */
@keyframes library-pocket-fade {
from {
fill: rgb(213,32,20);
fill: #ef4056;
}
to {
fill: inherit;
@ -218,7 +218,7 @@ panelmultiview[mainViewId=PanelUI-pocketView] > .panel-viewcontainer > .panel-vi
}
#pocket-button[cui-areatype="toolbar"][open] {
fill: rgb(213,32,20);
fill: #ef4056;
}
@media not all and (min-resolution: 1.1dppx) {

View File

@ -549,6 +549,7 @@ safebrowsing.reportedAttackSite=Reported Attack Site!
safebrowsing.notAnAttackButton.label=This isnt an attack site…
safebrowsing.notAnAttackButton.accessKey=A
safebrowsing.reportedUnwantedSite=Reported Unwanted Software Site!
safebrowsing.reportedHarmfulSite=Reported Harmful Site!
# Ctrl-Tab
# LOCALIZATION NOTE (ctrlTab.listAllTabs.label): #1 represents the number

View File

@ -243,14 +243,6 @@ this.E10SUtils = {
this.getRemoteTypeForURIObject(aURI, true, remoteType, webNav.currentURI);
}
if (sessionHistory.count == 1 && webNav.currentURI.spec == "about:newtab") {
// This is possibly a preloaded browser and we're about to navigate away for
// the first time. On the child side there is no way to tell for sure if that
// is the case, so let's redirect this request to the parent to decide if a new
// process is needed.
return false;
}
// If the URI can be loaded in the current process then continue
return this.shouldLoadURIInThisProcess(aURI);
},

View File

@ -861,12 +861,11 @@ html|span.ac-emphasize-text-url {
This is why we can't have nice things: */
/* Animations don't repaint properly without an X compositor. */
animation-name: none !important;
/* Opacity rounds to 0 or 1 on Linux without an X compositor so make the
background be transparent in that case by having all alpha values < 0.5 */
background-image: radial-gradient(50% 100%, rgba(0,149,220,0.3) 50%, rgba(0,149,220,0.49) 100%);
/* The highlight isn't anti-aliased without an X compositor so make it thicker.
Make it a darker color since we don't have the box-shadow in this case. */
border: 4px solid rgb(0,149,220);
/* Opacity rounds to 0 or 1 on Linux without an X compositor, making the
background color not visible. Anti-aliasing is not available either. Make a
thicker outline and cancel border-radius for that case. */
outline: 4px solid rgb(0,200,215);
border-radius: 0 !important;
}
#UITourTooltipDescription {

View File

@ -4,11 +4,6 @@
%include ../../../shared/incontentprefs/preferences.inc.css
prefpane .groupbox-title {
background: none;
margin-bottom: 0;
}
.actionsMenu > .menulist-label-box > .menulist-icon {
margin-top: 2px;
margin-inline-start: 2px;
@ -19,12 +14,10 @@ prefpane .groupbox-title {
padding-inline-start: 3px;
}
textbox + button {
margin-inline-start: -4px;
}
filefield + button {
margin-inline-start: -8px;
margin-top: 4px;
margin-bottom: 4px;
}
#popupPolicyRow {

View File

@ -28,11 +28,6 @@ prefpane .groupbox-body {
padding: 8px 4px 4px 4px;
}
prefpane .groupbox-title {
background: url("chrome://global/skin/50pct_transparent_grey.png") repeat-x bottom left;
margin-bottom: 4px;
}
tabpanels {
padding: 20px 7px 7px;
}

View File

@ -5,9 +5,16 @@
%endif
@namespace html "http://www.w3.org/1999/xhtml";
* {
-moz-user-select: text;
}
:root {
--in-content-category-background: #fafafc;
}
.main-content {
padding-top: 0;
background-color: #fafafc;
}
.pane-container {
@ -28,6 +35,10 @@
font-size: 1.36rem;
}
groupbox + groupbox {
margin-top: 16px;
}
input,
description.indent,
.indent > description {
@ -39,10 +50,6 @@ description.indent,
color: #737373;
}
* {
-moz-user-select: text;
}
button,
treecol,
html|option {
@ -50,34 +57,29 @@ html|option {
-moz-user-select: none;
}
caption > label {
font-size: 1.55rem;
font-weight: 600;
description,
label {
line-height: 30px;
margin-top: 0 !important;
margin-bottom: 0 !important;
}
#engineList treechildren::-moz-tree-image(engineShown, checked),
#blocklistsTree treechildren::-moz-tree-image(selectionCol, checked) {
list-style-image: url("chrome://global/skin/in-content/check.svg");
-moz-context-properties: fill, stroke;
fill: #2292d0;
stroke: none;
width: 21px;
height: 21px;
description > checkbox {
vertical-align: bottom;
}
#engineList treechildren::-moz-tree-image(engineShown, checked, selected),
#blocklistsTree treechildren::-moz-tree-image(selectionCol, checked, selected) {
fill: white;
stroke: #0095dd;
.indent {
margin-inline-start: 28px !important;
}
#engineList treechildren::-moz-tree-row,
#blocklistsTree treechildren::-moz-tree-row {
min-height: 36px;
separator.thin:not([orient="vertical"]) {
height: 8px;
}
#selectionCol {
min-width: 26px;
.checkbox-check {
margin-inline-end: 8px;
width: 20px;
height: 20px;
}
.learnMore {
@ -88,6 +90,15 @@ caption > label {
.accessory-button {
min-width: 145px;
margin: 2px 0;
}
.groupbox-title {
margin-top: 16px;
}
.groupbox-body {
margin-top: 4px;
}
/* Subcategory title */
@ -109,24 +120,6 @@ caption > label {
/* Category List */
#categories {
max-height: 100vh;
}
#categories > scrollbox {
overflow-x: hidden !important;
}
/**
* We want the last category to always have non-0 getBoundingClientRect().bottom
* so we can use the value to figure out the max-height of the list in
* preferences.js, so use collapse instead of display: none; if it's hidden
*/
#categories > .category[hidden="true"] {
display: -moz-box;
visibility: collapse;
}
#category-general > .category-icon {
list-style-image: url("chrome://browser/skin/preferences/in-content-new/general.svg");
}
@ -143,15 +136,6 @@ caption > label {
list-style-image: url("chrome://browser/skin/preferences/in-content-new/sync.svg");
}
@media (max-width: 800px) {
.category-name {
display: none;
}
.help-button {
font-size: 0 !important;
}
}
/* header */
.header {
display: flex;
@ -165,7 +149,12 @@ caption > label {
/* General Pane */
#startupGroup {
margin-top: 0px !important;
}
#startupTable {
margin-top: 32px;
border-collapse: collapse;
}
@ -173,8 +162,12 @@ caption > label {
padding: 0; /* remove the padding from html.css */
}
#startupTable > tr:not(:first-child) > td {
padding-top: 0.5em; /* add a spacing between the rows */
#startupTable > .tableGroup > td {
padding-top: 32px;
}
#startupTable > .tableSubGroup > td {
padding-top: 8px;
}
#startupTable > tr > .label-cell {
@ -182,6 +175,10 @@ caption > label {
width: 0; /* make the column as small as possible */
}
#startupTable > tr > .content-cell:not(:first-child) {
padding-inline-start: 8px;
}
#startupTable > tr > .label-cell > label {
white-space: nowrap;
}
@ -202,9 +199,8 @@ caption > label {
flex-grow: 1;
}
#useFirefoxSync {
font-size: 90%;
margin-inline-end: 8px !important;
.content-cell-item {
margin: 0 4px;
}
#getStarted {
@ -225,15 +221,34 @@ caption > label {
direction: rtl;
}
#defaultFontSizeLabel {
/* !important needed to override common !important rule */
margin-inline-start: 4px !important;
#updateApp > .groupbox-body > label {
margin: 0 0 4px 0;
line-height: 30px;
}
/* Applications Pane Styles */
#updateApp > .groupbox-body > description {
line-height: 30px;
margin: 0;
}
#updateBox {
margin-top: 8px;
margin-bottom: 32px;
}
#updateBox button {
margin-top: 0;
margin-bottom: 0;
}
#updateRadioGroup radio {
height: 30px;
margin: 2px 0;
}
#filter {
margin-inline-start: 0;
margin-bottom: 8px;
}
#handlersView {
@ -266,7 +281,51 @@ caption > label {
margin-inline-end: 8px !important;
}
/* Privacy pane */
/* Search Pane */
#defaultEngine {
margin-top: 2px;
margin-bottom: 6px;
}
#engineList {
margin: 2px 0 5px 0;
}
#engineList > treechildren::-moz-tree-image(engineShown, checked),
#blocklistsTree > treechildren::-moz-tree-image(selectionCol, checked) {
list-style-image: url("chrome://global/skin/in-content/check.svg");
-moz-context-properties: fill, stroke;
fill: #2292d0;
stroke: none;
width: 21px;
height: 21px;
}
#engineList > treechildren::-moz-tree-image(engineShown, checked, selected),
#blocklistsTree > treechildren::-moz-tree-image(selectionCol, checked, selected) {
fill: white;
stroke: #0095dd;
}
#engineList > treechildren::-moz-tree-row,
#blocklistsTree > treechildren::-moz-tree-row {
min-height: 36px;
}
#selectionCol {
min-width: 26px;
}
#addEnginesBox {
margin: 4px 0 0 0;
}
/* Privacy Pane */
#formAutofillGroup {
margin-top: 28px;
}
.doNotTrackLearnMore {
margin-inline-start: calc(1em + 30px);
@ -279,14 +338,28 @@ caption > label {
margin-left: 0;
}
#locationBarGroup > .text-link {
margin-top: 6px;
line-height: 30px;
}
#allowSmartSize {
margin-top: 0;
margin-bottom: 4px;
}
#doNotTrackLearnMoreBox {
margin-top: 30px
margin-top: 32px;
}
#trackingProtectionAdvancedSettings {
margin-inline-start: 15px;
}
#historyPane {
margin-top: 4px;
}
/* Collapse the non-active vboxes in decks to use only the height the
active vbox needs */
#historyPane:not([selectedIndex="1"]) > #historyDontRememberPane,
@ -297,16 +370,6 @@ caption > label {
visibility: collapse;
}
/* XXX This style is for bug 740213 and should be removed once that
bug has a solution. */
description > html|a {
cursor: pointer;
}
description > checkbox {
vertical-align: middle;
}
#weavePrefsDeck > vbox > label,
#weavePrefsDeck > vbox > groupbox,
#weavePrefsDeck > vbox > description,
@ -316,21 +379,10 @@ description > checkbox {
margin-inline-start: 0;
}
groupbox {
/* Give more available space for displaying tooltip on scrollable groupbox */
margin-top: 15px !important;
}
#tabsElement {
margin-inline-end: 4px; /* add the 4px end-margin of other elements */
}
.indent {
/* !important needed to override margin-inline-start:0 !important; rule
define in common.css for labels */
margin-inline-start: 33px !important;
}
.text-link {
margin-bottom: 0;
}
@ -374,6 +426,7 @@ groupbox {
}
.dialogBox > .groupbox-title {
margin-top: 0;
padding: 3.5px 0;
background-color: #F1F1F1;
border-bottom: 1px solid #C1C1C1;
@ -462,6 +515,11 @@ groupbox {
-moz-box-flex: 1;
}
#useFirefoxSync {
font-size: 90%;
margin-inline-end: 8px !important;
}
#noFxaGroup {
-moz-box-flex: 1;
margin: 0;
@ -481,8 +539,10 @@ groupbox {
}
#fxaSyncComputerName {
margin-inline-start: 0px;
-moz-box-flex: 1;
margin-top: 3px;
margin-inline-start: -4px;
margin-inline-end: 0;
margin-bottom: 0;
}
#tosPP-small-ToS {
@ -622,24 +682,24 @@ groupbox {
.help-button {
position: fixed;
left: 0;
/* Needs to have enough gap from the bottom to not
get behind the status panel (bug 1357841). */
bottom: 2rem;
bottom: 36px;
background-image: url("chrome://browser/skin/preferences/in-content-new/help.svg");
-moz-context-properties: fill, fill-opacity;
fill: currentColor;
fill-opacity: 0.8;
font-size: 13px;
line-height: 16px;
background-position: 15px;
padding-inline-start: 35px;
height: 16px;
background-position: 8px;
padding-inline-start: 38px;
margin-inline-start: 44px;
white-space: nowrap;
}
.help-button:-moz-locale-dir(rtl) {
background-position: right 8px top 0;
left: auto;
right: 0;
background-position: right 15px top 0;
}
.help-button:hover {
@ -677,7 +737,7 @@ groupbox {
#searchInput {
width: 250px;
margin: 20px 0;
margin: 20px 0 30px 0;
}
#searchInput .textbox-search-icons:not([selectedIndex="1"]) {

View File

@ -142,9 +142,11 @@ ifeq (,$(findstring -j,$(MOZ_MAKE_FLAGS)))
MOZ_MAKE_FLAGS += -j$(cores)
endif
ifdef MOZ_AUTOMATION
ifeq (4.0,$(firstword $(sort 4.0 $(MAKE_VERSION))))
MOZ_MAKE_FLAGS += --output-sync=line
endif
endif
ifdef MOZ_BUILD_PROJECTS

View File

@ -3,10 +3,20 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
const URL = "data:text/html;charset=utf8,test for textbox context menu";
// HTML inputs don't automatically get the 'edit' context menu, so we have
// a helper on the toolbox to do so. Make sure that shows menu items in the
// right state, and that it works for an input inside of a panel.
add_task(function* () {
let toolbox = yield openNewTabAndToolbox(URL, "inspector");
const URL = "data:text/html;charset=utf8,test for textbox context menu";
const textboxToolId = "test-tool-1";
registerCleanupFunction(() => {
gDevTools.unregisterTool(textboxToolId);
});
add_task(async function checkMenuEntryStates() {
info("Checking the state of edit menuitems with an empty clipboard");
let toolbox = await openNewTabAndToolbox(URL, "inspector");
let textboxContextMenu = toolbox.textBoxContextMenuPopup;
emptyClipboard();
@ -15,7 +25,7 @@ add_task(function* () {
let inspector = toolbox.getPanel("inspector");
let onFocus = once(inspector.searchBox, "focus");
inspector.searchBox.focus();
yield onFocus;
await onFocus;
ok(textboxContextMenu, "The textbox context menu is loaded in the toolbox");
@ -30,7 +40,7 @@ add_task(function* () {
let onContextMenuPopup = once(textboxContextMenu, "popupshowing");
textboxContextMenu.openPopupAtScreen(0, 0, true);
yield onContextMenuPopup;
await onContextMenuPopup;
is(cmdUndo.getAttribute("disabled"), "true", "cmdUndo is disabled");
is(cmdDelete.getAttribute("disabled"), "true", "cmdDelete is disabled");
@ -41,11 +51,41 @@ add_task(function* () {
is(cmdCut.getAttribute("disabled"), "", "cmdCut is enabled");
is(cmdCopy.getAttribute("disabled"), "", "cmdCopy is enabled");
is(cmdPaste.getAttribute("disabled"), "", "cmdPaste is enabled");
yield cleanup(toolbox);
});
function* cleanup(toolbox) {
yield toolbox.destroy();
gBrowser.removeCurrentTab();
add_task(async function automaticallyBindTexbox() {
info("Registering a tool with an input field and making sure the context menu works");
gDevTools.registerTool({
id: textboxToolId,
isTargetSupported: () => true,
url: "data:text/html;charset=utf8,<input />",
label: "Context menu works without tool intervention",
build: function (iframeWindow, toolbox) {
this.panel = createTestPanel(iframeWindow, toolbox);
return this.panel.open();
},
});
let toolbox = await openNewTabAndToolbox(URL, textboxToolId);
is(toolbox.currentToolId, textboxToolId, "The custom tool has been opened");
await checkTextBox(toolbox.getCurrentPanel().document.querySelector("input"), toolbox);
});
async function checkTextBox(textBox, {textBoxContextMenuPopup}) {
is(textBoxContextMenuPopup.state, "closed", "The menu is closed");
info("Simulating context click on the textbox and expecting the menu to open");
let onContextMenu = once(textBoxContextMenuPopup, "popupshown");
EventUtils.synthesizeMouse(textBox, 2, 2, {type: "contextmenu", button: 2},
textBox.ownerDocument.defaultView);
await onContextMenu;
is(textBoxContextMenuPopup.state, "open", "The menu is now visible");
info("Closing the menu");
let onContextMenuHidden = once(textBoxContextMenuPopup, "popuphidden");
textBoxContextMenuPopup.hidePopup();
await onContextMenuHidden;
is(textBoxContextMenuPopup.state, "closed", "The menu is closed again");
}

View File

@ -203,6 +203,7 @@ function DevToolPanel(iframeWindow, toolbox) {
EventEmitter.decorate(this);
this._toolbox = toolbox;
this._window = iframeWindow;
}
DevToolPanel.prototype = {
@ -218,6 +219,10 @@ DevToolPanel.prototype = {
return deferred.promise;
},
get document() {
return this._window.document;
},
get target() {
return this._toolbox.target;
},

View File

@ -442,6 +442,13 @@ Toolbox.prototype = {
this.doc.getElementById("toolbox-textbox-context-popup");
this.textBoxContextMenuPopup.addEventListener("popupshowing",
this._updateTextBoxMenuItems, true);
this.doc.addEventListener("contextmenu", (e) => {
if (e.originalTarget.closest("input") || e.originalTarget.closest("textarea")) {
e.stopPropagation();
e.preventDefault();
this.openTextBoxContextMenu(e.screenX, e.screenY);
}
}, true);
this.shortcuts = new KeyShortcuts({
window: this.doc.defaultView

View File

@ -324,7 +324,6 @@ BoxModel.prototype = {
this.store.dispatch(updateLayout(layout));
}, e => console.error(e));
},
contextMenu: this.inspector.onTextBoxContextMenu,
cssProperties: getCssProperties(this.inspector.toolbox)
}, event);
},

View File

@ -193,7 +193,6 @@ function CssComputedView(inspector, document, pageStyle) {
this.element.addEventListener("click", this._onClick);
this.element.addEventListener("contextmenu", this._onContextMenu);
this.searchField.addEventListener("input", this._onFilterStyles);
this.searchField.addEventListener("contextmenu", this.inspector.onTextBoxContextMenu);
this.searchClearButton.addEventListener("click", this._onClearSearch);
this.includeBrowserStylesCheckbox.addEventListener("input",
this._onIncludeBrowserStyles);
@ -781,8 +780,6 @@ CssComputedView.prototype = {
this.styleDocument.removeEventListener("copy", this._onCopy);
this.element.removeEventListener("contextmenu", this._onContextMenu);
this.searchField.removeEventListener("input", this._onFilterStyles);
this.searchField.removeEventListener("contextmenu",
this.inspector.onTextBoxContextMenu);
this.searchClearButton.removeEventListener("click", this._onClearSearch);
this.includeBrowserStylesCheckbox.removeEventListener("input",
this._onIncludeBrowserStyles);

View File

@ -7,7 +7,6 @@
const { addons, createClass, createFactory, DOM: dom, PropTypes } =
require("devtools/client/shared/vendor/react");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const { findDOMNode } = require("devtools/client/shared/vendor/react-dom");
const SearchBox = createFactory(require("devtools/client/shared/components/search-box"));
const FontList = createFactory(require("./FontList"));
@ -25,25 +24,10 @@ const App = createClass({
fonts: PropTypes.arrayOf(PropTypes.shape(Types.font)).isRequired,
onPreviewFonts: PropTypes.func.isRequired,
onShowAllFont: PropTypes.func.isRequired,
onTextBoxContextMenu: PropTypes.func.isRequired,
},
mixins: [ addons.PureRenderMixin ],
componentDidMount() {
let { onTextBoxContextMenu } = this.props;
let searchInput = findDOMNode(this).querySelector(".devtools-textinput");
searchInput.addEventListener("contextmenu", onTextBoxContextMenu);
},
componentWillUnmount() {
let { onTextBoxContextMenu } = this.props;
let searchInput = findDOMNode(this).querySelector(".devtools-textinput");
searchInput.removeEventListener("contextmenu", onTextBoxContextMenu);
},
render() {
let {
fonts,

View File

@ -47,7 +47,6 @@ FontInspector.prototype = {
let app = App({
onPreviewFonts: this.onPreviewFonts,
onShowAllFont: this.onShowAllFont,
onTextBoxContextMenu: this.inspector.onTextBoxContextMenu
});
let provider = createElement(Provider, {

View File

@ -44,7 +44,6 @@ function InspectorSearch(inspector, input, clearBtn) {
this._onClearSearch = this._onClearSearch.bind(this);
this.searchBox.addEventListener("keydown", this._onKeyDown, true);
this.searchBox.addEventListener("input", this._onInput, true);
this.searchBox.addEventListener("contextmenu", this.inspector.onTextBoxContextMenu);
this.searchClearButton.addEventListener("click", this._onClearSearch);
// For testing, we need to be able to wait for the most recent node request
@ -65,8 +64,6 @@ InspectorSearch.prototype = {
destroy: function () {
this.searchBox.removeEventListener("keydown", this._onKeyDown, true);
this.searchBox.removeEventListener("input", this._onInput, true);
this.searchBox.removeEventListener("contextmenu",
this.inspector.onTextBoxContextMenu);
this.searchClearButton.removeEventListener("click", this._onClearSearch);
this.searchBox = null;
this.searchClearButton = null;

View File

@ -123,7 +123,6 @@ function Inspector(toolbox) {
this.onSidebarHidden = this.onSidebarHidden.bind(this);
this.onSidebarSelect = this.onSidebarSelect.bind(this);
this.onSidebarShown = this.onSidebarShown.bind(this);
this.onTextBoxContextMenu = this.onTextBoxContextMenu.bind(this);
this._target.on("will-navigate", this._onBeforeNavigate);
this._detectingActorFeatures = this._detectActorFeatures();
@ -1062,17 +1061,6 @@ Inspector.prototype = {
});
},
/**
* This is meant to be called by all the search, filter, inplace text boxes in the
* inspector, and just calls through to the toolbox openTextBoxContextMenu helper.
* @param {DOMEvent} e
*/
onTextBoxContextMenu: function (e) {
e.stopPropagation();
e.preventDefault();
this.toolbox.openTextBoxContextMenu(e.screenX, e.screenY);
},
_openMenu: function ({ target, screenX = 0, screenY = 0 } = { }) {
let markupContainer = this.markup.getContainer(this.selection.nodeFront);

View File

@ -69,7 +69,6 @@ function ElementEditor(container, node) {
trigger: "dblclick",
stopOnReturn: true,
done: this.onTagEdit.bind(this),
contextMenu: this.markup.inspector.onTextBoxContextMenu,
cssProperties: this._cssProperties
});
}
@ -97,7 +96,6 @@ function ElementEditor(container, node) {
undoMods.apply();
});
},
contextMenu: this.markup.inspector.onTextBoxContextMenu,
cssProperties: this._cssProperties
});
@ -402,7 +400,6 @@ ElementEditor.prototype = {
undoMods.apply();
});
},
contextMenu: this.markup.inspector.onTextBoxContextMenu,
cssProperties: this._cssProperties
});

View File

@ -55,7 +55,6 @@ function TextEditor(container, node, type) {
});
},
cssProperties: getCssProperties(this.markup.toolbox),
contextMenu: this.markup.inspector.onTextBoxContextMenu
});
this.update();

View File

@ -150,7 +150,6 @@ function CssRuleView(inspector, document, store, pageStyle) {
this.element.addEventListener("contextmenu", this._onContextMenu);
this.addRuleButton.addEventListener("click", this._onAddRule);
this.searchField.addEventListener("input", this._onFilterStyles);
this.searchField.addEventListener("contextmenu", this.inspector.onTextBoxContextMenu);
this.searchClearButton.addEventListener("click", this._onClearSearch);
this.pseudoClassToggle.addEventListener("click", this._onTogglePseudoClassPanel);
this.classToggle.addEventListener("click", this._onToggleClassPanel);
@ -701,8 +700,6 @@ CssRuleView.prototype = {
this.element.removeEventListener("contextmenu", this._onContextMenu);
this.addRuleButton.removeEventListener("click", this._onAddRule);
this.searchField.removeEventListener("input", this._onFilterStyles);
this.searchField.removeEventListener("contextmenu",
this.inspector.onTextBoxContextMenu);
this.searchClearButton.removeEventListener("click", this._onClearSearch);
this.pseudoClassToggle.removeEventListener("click", this._onTogglePseudoClassPanel);
this.classToggle.removeEventListener("click", this._onToggleClassPanel);

View File

@ -45,7 +45,7 @@ support-files =
!/devtools/client/shared/test/test-actor-registry.js
[browser_rules_add-property-and-reselect.js]
skip-if = stylo # Bug 1384802 - Empty rules aren't returned
skip-if = stylo # Bug 1387445
[browser_rules_add-property-cancel_01.js]
[browser_rules_add-property-cancel_02.js]
[browser_rules_add-property-cancel_03.js]
@ -54,22 +54,14 @@ skip-if = stylo # Bug 1384802 - Empty rules aren't returned
[browser_rules_add-property_02.js]
[browser_rules_add-property-svg.js]
[browser_rules_add-rule-and-property.js]
skip-if = stylo # Bug 1384802 - Empty rules aren't returned
[browser_rules_add-rule-button-state.js]
[browser_rules_add-rule-edit-selector.js]
skip-if = stylo # Bug 1384802 - Empty rules aren't returned
[browser_rules_add-rule-iframes.js]
skip-if = stylo # Bug 1384802 - Empty rules aren't returned
[browser_rules_add-rule-namespace-elements.js]
skip-if = stylo # Bug 1384802 - Empty rules aren't returned
[browser_rules_add-rule-pseudo-class.js]
skip-if = stylo # Bug 1384802 - Empty rules aren't returned
[browser_rules_add-rule-then-property-edit-selector.js]
skip-if = stylo # Bug 1384802 - Empty rules aren't returned
[browser_rules_add-rule-with-menu.js]
skip-if = stylo # Bug 1384802 - Empty rules aren't returned
[browser_rules_add-rule.js]
skip-if = stylo # Bug 1384802 - Empty rules aren't returned
[browser_rules_authored.js]
[browser_rules_authored_color.js]
[browser_rules_authored_override.js]
@ -116,7 +108,7 @@ skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32
[browser_rules_cubicbezier-commit-on-ENTER.js]
[browser_rules_cubicbezier-revert-on-ESC.js]
[browser_rules_custom.js]
skip-if = stylo # Bug 1384802 - Empty rules aren't returned
skip-if = stylo # Bug 1387445
[browser_rules_cycle-angle.js]
[browser_rules_cycle-color.js]
[browser_rules_edit-display-grid-property.js]
@ -127,7 +119,6 @@ skip-if = (os == "linux") # Bug 1356214
[browser_rules_edit-property-computed.js]
[browser_rules_edit-property-increments.js]
[browser_rules_edit-property-order.js]
skip-if = stylo # Bug 1384802 - Empty rules aren't returned
[browser_rules_edit-property-remove_01.js]
[browser_rules_edit-property-remove_02.js]
[browser_rules_edit-property-remove_03.js]
@ -137,7 +128,7 @@ skip-if = stylo # Bug 1384802 - Empty rules aren't returned
[browser_rules_edit-property_04.js]
[browser_rules_edit-property_05.js]
[browser_rules_edit-property_06.js]
skip-if = stylo # Bug 1384802 - Empty rules aren't returned
skip-if = stylo # Bug 1387445
[browser_rules_edit-property_07.js]
[browser_rules_edit-property_08.js]
[browser_rules_edit-property_09.js]
@ -145,16 +136,12 @@ skip-if = stylo # Bug 1384802 - Empty rules aren't returned
[browser_rules_edit-selector-click-on-scrollbar.js]
skip-if = os == "mac" # Bug 1245996 : click on scrollbar not working on OSX
[browser_rules_edit-selector-commit.js]
skip-if = stylo # Bug 1384802 - Empty rules aren't returned
[browser_rules_edit-selector_01.js]
[browser_rules_edit-selector_02.js]
skip-if = stylo # Bug 1384802 - Empty rules aren't returned
[browser_rules_edit-selector_03.js]
[browser_rules_edit-selector_04.js]
[browser_rules_edit-selector_05.js]
skip-if = stylo # Bug 1384802 - Empty rules aren't returned
[browser_rules_edit-selector_06.js]
skip-if = stylo # Bug 1384802 - Empty rules aren't returned
[browser_rules_edit-selector_07.js]
[browser_rules_edit-selector_08.js]
[browser_rules_edit-selector_09.js]
@ -183,7 +170,6 @@ skip-if = (os == "win" && debug) # bug 963492: win.
[browser_rules_grid-toggle_03.js]
[browser_rules_grid-toggle_04.js]
[browser_rules_guessIndentation.js]
skip-if = stylo # Bug 1384802 - Empty rules aren't returned
[browser_rules_inherited-properties_01.js]
[browser_rules_inherited-properties_02.js]
[browser_rules_inherited-properties_03.js]
@ -193,22 +179,21 @@ skip-if = stylo # Bug 1384802 - Empty rules aren't returned
[browser_rules_invalid-source-map.js]
[browser_rules_keybindings.js]
[browser_rules_keyframes-rule_01.js]
skip-if = stylo # Bug 1384802 - Empty rules aren't returned
skip-if = stylo # Bug 1387445
[browser_rules_keyframes-rule_02.js]
skip-if = stylo # Bug 1384802 - Empty rules aren't returned
skip-if = stylo # Bug 1387445
[browser_rules_keyframeLineNumbers.js]
skip-if = stylo # Bug 1384802 - Empty rules aren't returned
skip-if = stylo # Bug 1387445
[browser_rules_lineNumbers.js]
[browser_rules_livepreview.js]
[browser_rules_mark_overridden_01.js]
[browser_rules_mark_overridden_02.js]
[browser_rules_mark_overridden_03.js]
skip-if = stylo # Bug 1384802 - Empty rules aren't returned
skip-if = stylo # Bug 1387445
[browser_rules_mark_overridden_04.js]
[browser_rules_mark_overridden_05.js]
[browser_rules_mark_overridden_06.js]
[browser_rules_mark_overridden_07.js]
skip-if = stylo # Bug 1384802 - Empty rules aren't returned
[browser_rules_mathml-element.js]
[browser_rules_media-queries.js]
[browser_rules_multiple-properties-duplicates.js]
@ -234,7 +219,7 @@ skip-if = stylo # Bug 1384802 - Empty rules aren't returned
[browser_rules_search-filter-overridden-property.js]
[browser_rules_search-filter_01.js]
[browser_rules_search-filter_02.js]
skip-if = stylo # Bug 1384802 - Empty rules aren't returned
skip-if = stylo # Bug 1387445
[browser_rules_search-filter_03.js]
[browser_rules_search-filter_04.js]
[browser_rules_search-filter_05.js]
@ -257,7 +242,6 @@ skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32
[browser_rules_selector-highlighter_04.js]
[browser_rules_selector-highlighter_05.js]
[browser_rules_selector_highlight.js]
skip-if = stylo # Bug 1384802 - Empty rules aren't returned
[browser_rules_shapes-toggle_01.js]
[browser_rules_shapes-toggle_02.js]
[browser_rules_shapes-toggle_03.js]

View File

@ -144,7 +144,6 @@ RuleEditor.prototype = {
element: this.selectorText,
done: this._onSelectorDone,
cssProperties: this.rule.cssProperties,
contextMenu: this.ruleView.inspector.onTextBoxContextMenu
});
}
@ -463,7 +462,6 @@ RuleEditor.prototype = {
contentType: InplaceEditor.CONTENT_TYPES.CSS_PROPERTY,
popup: this.ruleView.popup,
cssProperties: this.rule.cssProperties,
contextMenu: this.ruleView.inspector.onTextBoxContextMenu
});
// Auto-close the input if multiple rules get pasted into new property.

View File

@ -228,7 +228,6 @@ TextPropertyEditor.prototype = {
contentType: InplaceEditor.CONTENT_TYPES.CSS_PROPERTY,
popup: this.popup,
cssProperties: this.cssProperties,
contextMenu: this.ruleView.inspector.onTextBoxContextMenu
});
// Auto blur name field on multiple CSS rules get pasted in.
@ -300,7 +299,6 @@ TextPropertyEditor.prototype = {
multiline: true,
maxWidth: () => this.container.getBoundingClientRect().width,
cssProperties: this.cssProperties,
contextMenu: this.ruleView.inspector.onTextBoxContextMenu
});
this.ruleView.highlighters.on("hover-shape-point", this._onHoverShapePoint);

View File

@ -101,7 +101,6 @@ skip-if = e10s && debug # Bug 1252201 - Docshell leak on debug e10s
[browser_styleeditor_sync.js]
[browser_styleeditor_syncAddProperty.js]
[browser_styleeditor_syncAddRule.js]
skip-if = stylo # Bug 1384802 - Empty rules aren't returned
[browser_styleeditor_syncAlreadyOpen.js]
[browser_styleeditor_syncEditSelector.js]
[browser_styleeditor_syncIntoRuleView.js]

View File

@ -0,0 +1,50 @@
# Console Tests
The console panel uses currently two different frameworks for tests:
* Mochitest - [Mochitest](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Mochitest) is an automated testing framework built on top of the MochiKit JavaScript libraries. It's just one of the automated regression testing frameworks used by Mozilla
* Mocha + Enzyme - [mocha](https://mochajs.org/) Mocha is JavaScript test framework running on Node.js
[Enzyme](http://airbnb.io/enzyme/) is a JavaScript Testing utility for React that makes it easier to assert, manipulate, and traverse your React Components' output.
The team is leaning towards Enzyme since it's well known and suitable for React.
It's also easier to contribute to tests written on top of Enzyme.
# Stubs
Many tests depends on fix data structures (aka stubs) that mimic
<abbr title="Remote Debugging Protocol">RDP<abbr> packets that represents Console logs.
Stubs are stored in `test/fixtures` directory and you might automatically generate them.
## Append new Console API stubs
See how to generate stubs for Console API calls.
* Append new entry into `consoleApiCommands` array. The array is defined in this module:
`\test\fixtures\stub-generators\stub-snippets.js`
* Generate stubs with existing mochitest:
`\test\fixtures\stub-generators\browser_webconsole_check_stubs_console_api.js`
Run the generator using `mach` command.
`./mach test devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/browser_webconsole_check_stubs_console_api.js`
## Append new CSS Messages stubs
See how to generate stubs for CSS messages.
* Append new entry into `cssMessage` map into `stub-snippets.js`
* Generate stubs with: `browser_webconsole_check_stubs_css_message.js`
## Append new Evaluation Result stubs
See how to generate stubs for evaluation results.
* Append new entry into `evaluationResultCommands` map into `stub-snippets.js`
* Generate stubs with: `browser_webconsole_check_stubs_evaluation_result.js`
## Append new Network Events stubs
See how to generate stubs for network events
* Append new entry into `networkEvent` map into `stub-snippets.js`
* Generate stubs with: `browser_webconsole_update_stubs_network_event.js`
## Append new Page Error stubs
See how to generate stubs for page errors.
* Append new entry into `pageError` array into `stub-snippets.js`
* Generate stubs with: `browser_webconsole_update_stubs_page_error.js`

View File

@ -89,7 +89,7 @@ struct DevTools : public ::testing::Test {
/* Create the global object. */
JS::RootedObject newGlobal(cx);
JS::CompartmentOptions options;
options.behaviors().setVersion(JSVERSION_LATEST);
options.behaviors().setVersion(JSVERSION_DEFAULT);
newGlobal = JS_NewGlobalObject(cx, getGlobalClass(), nullptr,
JS::FireOnNewGlobalHook, options);
if (!newGlobal)

View File

@ -123,7 +123,8 @@ DOMImplementation::CreateDocument(const nsAString& aNamespaceURI,
mDocumentURI, mBaseURI,
mOwner->NodePrincipal(),
true, scriptHandlingObject,
DocumentFlavorLegacyGuess);
DocumentFlavorLegacyGuess,
mOwner->GetStyleBackendType());
NS_ENSURE_SUCCESS(rv, rv);
// When DOMImplementation's createDocument method is invoked with
@ -202,7 +203,8 @@ DOMImplementation::CreateHTMLDocument(const nsAString& aTitle,
doctype, mDocumentURI, mBaseURI,
mOwner->NodePrincipal(),
true, scriptHandlingObject,
DocumentFlavorLegacyGuess);
DocumentFlavorLegacyGuess,
mOwner->GetStyleBackendType());
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocument> doc = do_QueryInterface(document);

View File

@ -461,6 +461,13 @@ DOMParser::SetUpDocument(DocumentFlavor aFlavor, nsIDOMDocument** aResult)
NS_ENSURE_SUCCESS(rv, rv);
}
// Try to inherit a style backend.
auto styleBackend = StyleBackendType::None;
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mScriptHandlingObject);
if (window && window->GetExtantDoc()) {
styleBackend = window->GetExtantDoc()->GetStyleBackendType();
}
NS_ASSERTION(mPrincipal, "Must have principal by now");
NS_ASSERTION(mDocumentURI, "Must have document URI by now");
@ -469,5 +476,6 @@ DOMParser::SetUpDocument(DocumentFlavor aFlavor, nsIDOMDocument** aResult)
mPrincipal,
true,
scriptHandlingObject,
aFlavor);
aFlavor,
styleBackend);
}

View File

@ -5200,7 +5200,8 @@ nsContentUtils::ConvertToPlainText(const nsAString& aSourceBuffer,
principal,
true,
nullptr,
DocumentFlavorHTML);
DocumentFlavorHTML,
StyleBackendType::None);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument);

View File

@ -9939,7 +9939,8 @@ nsDocument::GetTemplateContentsOwner()
NodePrincipal(),
true, // aLoadedAsData
scriptObject, // aEventObject
DocumentFlavorHTML);
DocumentFlavorHTML,
mStyleBackendType);
NS_ENSURE_SUCCESS(rv, nullptr);
mTemplateContentsOwner = do_QueryInterface(domDocument);
@ -12603,6 +12604,12 @@ nsIDocument::Constructor(const GlobalObject& aGlobal,
return nullptr;
}
auto styleBackend = StyleBackendType::None;
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global);
if (window && window->GetExtantDoc()) {
styleBackend = window->GetExtantDoc()->GetStyleBackendType();
}
nsCOMPtr<nsIScriptObjectPrincipal> prin = do_QueryInterface(aGlobal.GetAsSupports());
if (!prin) {
rv.Throw(NS_ERROR_UNEXPECTED);
@ -12627,7 +12634,8 @@ nsIDocument::Constructor(const GlobalObject& aGlobal,
prin->GetPrincipal(),
true,
global,
DocumentFlavorPlain);
DocumentFlavorPlain,
styleBackend);
if (NS_FAILED(res)) {
rv.Throw(res);
return nullptr;

View File

@ -1662,7 +1662,7 @@ nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript(
return;
}
JS::CompileOptions options(cx, JSVERSION_LATEST);
JS::CompileOptions options(cx, JSVERSION_DEFAULT);
options.setFileAndLine(url.get(), 1);
options.setNoScriptRval(true);
@ -1728,7 +1728,7 @@ nsMessageManagerScriptExecutor::InitChildGlobalInternal(
JS::CompartmentOptions options;
options.creationOptions().setSystemZone();
options.behaviors().setVersion(JSVERSION_LATEST);
options.behaviors().setVersion(JSVERSION_DEFAULT);
if (xpc::SharedMemoryEnabled()) {
options.creationOptions().setSharedMemoryAndAtomicsEnabled(true);

View File

@ -2231,7 +2231,6 @@ GK_ATOM(DisplayPortMargins, "_displayportmargins")
GK_ATOM(DisplayPortBase, "_displayportbase")
GK_ATOM(AsyncScrollLayerCreationFailed, "_asyncscrolllayercreationfailed")
GK_ATOM(forcemessagemanager, "forcemessagemanager")
GK_ATOM(isPreloadBrowser, "isPreloadBrowser")
// Names for system metrics
GK_ATOM(color_picker_available, "color-picker-available")

View File

@ -3634,7 +3634,8 @@ NS_NewDOMDocument(nsIDOMDocument** aInstancePtrResult,
nsIPrincipal* aPrincipal,
bool aLoadedAsData,
nsIGlobalObject* aEventObject,
DocumentFlavor aFlavor);
DocumentFlavor aFlavor,
mozilla::StyleBackendType aStyleBackend);
// This is used only for xbl documents created from the startup cache.
// Non-cached documents are created in the same manner as xml documents.
@ -3642,7 +3643,8 @@ nsresult
NS_NewXBLDocument(nsIDOMDocument** aInstancePtrResult,
nsIURI* aDocumentURI,
nsIURI* aBaseURI,
nsIPrincipal* aPrincipal);
nsIPrincipal* aPrincipal,
mozilla::StyleBackendType aStyleBackend);
nsresult
NS_NewPluginDocument(nsIDocument** aInstancePtrResult);

View File

@ -1,7 +1,6 @@
[DEFAULT]
support-files =
audio.ogg
dummy.html
empty.html
file_audioLoop.html
file_audioLoopInIframe.html
@ -36,7 +35,6 @@ tags = mcb
[browser_force_process_selector.js]
skip-if = !e10s # this only makes sense with e10s-multi
[browser_messagemanager_loadprocessscript.js]
[browser_aboutnewtab_process_selection.js]
[browser_messagemanager_targetframeloader.js]
[browser_messagemanager_unload.js]
[browser_pagehide_on_tab_close.js]

View File

@ -1,76 +0,0 @@
const TEST_URL = "http://www.example.com/browser/dom/base/test/dummy.html";
var ppmm = Services.ppmm;
add_task(async function(){
// We want to count processes in this test, so let's disable the pre-allocated process manager.
await SpecialPowers.pushPrefEnv({"set": [
["dom.ipc.processPrelaunch.enabled", false],
["dom.ipc.processCount", 10],
["dom.ipc.keepProcessesAlive.web", 10],
]});
});
// Ensure that the preloaded browser exists, and it's finished loading.
async function ensurePreloaded(gBrowser) {
gBrowser._createPreloadBrowser();
// We cannot use the regular BrowserTestUtils helper for waiting here, since that
// would try to insert the preloaded browser, which would only break things.
await BrowserTestUtils.waitForCondition( () => {
return gBrowser._preloadedBrowser.contentDocument.readyState == "complete";
});
}
add_task(async function(){
// This test is only relevant in e10s.
if (!gMultiProcessBrowser)
return;
ppmm.releaseCachedProcesses();
// Wait for the preloaded browser to load.
await ensurePreloaded(gBrowser);
// Store the number of processes (note: +1 for the parent process).
const { childCount: originalChildCount } = ppmm;
// Use the preloaded browser and create another one.
BrowserOpenTab();
let tab1 = gBrowser.selectedTab;
await ensurePreloaded(gBrowser);
// Check that the process count did not change.
is(ppmm.childCount, originalChildCount, "Preloaded browser should not create a new content process.")
// Let's do another round.
BrowserOpenTab();
let tab2 = gBrowser.selectedTab;
await ensurePreloaded(gBrowser);
// Check that the process count did not change.
is(ppmm.childCount, originalChildCount, "Preloaded browser should (still) not create a new content process.")
// Navigate to a content page from the parent side.
tab2.linkedBrowser.loadURI(TEST_URL);
await BrowserTestUtils.browserLoaded(tab2.linkedBrowser, false, TEST_URL);
is(ppmm.childCount, originalChildCount + 1,
"Navigating away from the preloaded browser (parent side) should create a new content process.")
// Navigate to a content page from the child side.
await BrowserTestUtils.switchTab(gBrowser, tab1);
await ContentTask.spawn(tab1.linkedBrowser, null, async function() {
const TEST_URL = "http://www.example.com/browser/dom/base/test/dummy.html";
content.location.href = TEST_URL;
});
await BrowserTestUtils.browserLoaded(tab1.linkedBrowser, false, TEST_URL);
is(ppmm.childCount, originalChildCount + 2,
"Navigating away from the preloaded browser (child side) should create a new content process.")
await BrowserTestUtils.removeTab(tab1);
await BrowserTestUtils.removeTab(tab2);
// Since we kept alive all the processes, we can shut down the ones that do
// not host any tabs reliably.
ppmm.releaseCachedProcesses();
is(ppmm.childCount, originalChildCount, "We're back to the original process count.");
});

View File

@ -1,9 +0,0 @@
<html>
<head>
<title>Dummy test page</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"></meta>
</head>
<body>
<p>Dummy test page</p>
</body>
</html>

View File

@ -185,6 +185,11 @@ const kEventConstructors = {
return new MediaQueryListEvent(aName, aProps);
},
},
MediaRecorderErrorEvent: { create: function (aName, aProps) {
aProps.error = new DOMException();
return new MediaRecorderErrorEvent(aName, aProps);
},
},
MediaStreamEvent: { create: function (aName, aProps) {
return new MediaStreamEvent(aName, aProps);
},
@ -287,10 +292,6 @@ const kEventConstructors = {
return new ProgressEvent(aName, aProps);
},
},
RecordErrorEvent: { create: function (aName, aProps) {
return new RecordErrorEvent(aName, aProps);
},
},
RTCDataChannelEvent: { create: function (aName, aProps) {
return new RTCDataChannelEvent(aName, aProps);
},

View File

@ -53,11 +53,7 @@ function done() {
SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout("untriaged");
addLoadEvent(function() {
SpecialPowers.pushPrefEnv({"set": [
["browser.newtab.preload", false]
]}, doTest);
});
addLoadEvent(doTest);
</script>

View File

@ -1568,8 +1568,9 @@ nsTextEditorState::PrepareEditor(const nsAString *aValue)
editorFlags |= nsIPlaintextEditor::eEditorDisabledMask;
// Disable the selection if necessary.
if (editorFlags & nsIPlaintextEditor::eEditorDisabledMask)
if (newTextEditor->IsDisabled()) {
mSelCon->SetDisplaySelection(nsISelectionController::SELECTION_OFF);
}
newTextEditor->SetFlags(editorFlags);
}
@ -2572,7 +2573,7 @@ nsTextEditorState::SetValue(const nsAString& aValue, const nsAString* aOldValue,
mValueBeingSet = aValue;
mIsCommittingComposition = true;
RefPtr<TextEditor> textEditor = mTextEditor;
nsresult rv = textEditor->ForceCompositionEnd();
nsresult rv = textEditor->CommitComposition();
if (!self.get()) {
return true;
}

View File

@ -762,11 +762,11 @@ ContentParent::MinTabSelect(const nsTArray<ContentParent*>& aContentParents,
/*static*/ already_AddRefed<ContentParent>
ContentParent::GetNewOrUsedBrowserProcess(const nsAString& aRemoteType,
ProcessPriority aPriority,
ContentParent* aOpener,
bool aPreferUsed)
ContentParent* aOpener)
{
nsTArray<ContentParent*>& contentParents = GetOrCreatePool(aRemoteType);
uint32_t maxContentParents = GetMaxProcessCount(aRemoteType);
if (aRemoteType.EqualsLiteral(LARGE_ALLOCATION_REMOTE_TYPE)) {
// We never want to re-use Large-Allocation processes.
if (contentParents.Length() >= maxContentParents) {
@ -775,18 +775,11 @@ ContentParent::GetNewOrUsedBrowserProcess(const nsAString& aRemoteType,
aOpener);
}
} else {
uint32_t numberOfParents = contentParents.Length();
nsTArray<nsIContentProcessInfo*> infos(numberOfParents);
nsTArray<nsIContentProcessInfo*> infos(contentParents.Length());
for (auto* cp : contentParents) {
infos.AppendElement(cp->mScriptableHelper);
}
if (aPreferUsed && numberOfParents) {
// For the preloaded browser we don't want to create a new process but reuse an
// existing one.
maxContentParents = numberOfParents;
}
nsCOMPtr<nsIContentProcessProvider> cpp =
do_GetService("@mozilla.org/ipc/processselector;1");
nsIContentProcessInfo* openerInfo = aOpener ? aOpener->mScriptableHelper.get() : nullptr;
@ -1138,13 +1131,6 @@ ContentParent::CreateBrowser(const TabContext& aContext,
remoteType.AssignLiteral(DEFAULT_REMOTE_TYPE);
}
bool isPreloadBrowser = false;
nsAutoString isPreloadBrowserStr;
if (aFrameElement->GetAttr(kNameSpaceID_None, nsGkAtoms::isPreloadBrowser,
isPreloadBrowserStr)) {
isPreloadBrowser = isPreloadBrowserStr.EqualsLiteral("true");
}
RefPtr<nsIContentParent> constructorSender;
if (isInContentProcess) {
MOZ_ASSERT(aContext.IsMozBrowserElement() || aContext.IsJSPlugin());
@ -1160,8 +1146,7 @@ ContentParent::CreateBrowser(const TabContext& aContext,
initialPriority);
} else {
constructorSender =
GetNewOrUsedBrowserProcess(remoteType, initialPriority,
nullptr, isPreloadBrowser);
GetNewOrUsedBrowserProcess(remoteType, initialPriority, nullptr);
}
if (!constructorSender) {
return nullptr;

View File

@ -172,8 +172,7 @@ public:
GetNewOrUsedBrowserProcess(const nsAString& aRemoteType = NS_LITERAL_STRING(NO_REMOTE_TYPE),
hal::ProcessPriority aPriority =
hal::ProcessPriority::PROCESS_PRIORITY_FOREGROUND,
ContentParent* aOpener = nullptr,
bool aPreferUsed = false);
ContentParent* aOpener = nullptr);
/**
* Get or create a content process for a JS plugin. aPluginID is the id of the JS plugin

View File

@ -17,7 +17,7 @@
#include "mozilla/dom/AudioStreamTrack.h"
#include "mozilla/dom/BlobEvent.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/RecordErrorEvent.h"
#include "mozilla/dom/MediaRecorderErrorEvent.h"
#include "mozilla/dom/VideoStreamTrack.h"
#include "nsAutoPtr.h"
#include "nsContentUtils.h"
@ -109,6 +109,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MediaRecorder,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMStream)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioNode)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSecurityDomException)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUnknownDomException)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@ -116,6 +118,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MediaRecorder,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStream)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAudioNode)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSecurityDomException)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mUnknownDomException)
tmp->UnRegisterActivityObserver();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@ -1055,6 +1059,9 @@ void
MediaRecorder::Start(const Optional<int32_t>& aTimeSlice, ErrorResult& aResult)
{
LOG(LogLevel::Debug, ("MediaRecorder.Start %p", this));
InitializeDomExceptions();
if (mState != RecordingState::Inactive) {
aResult.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
@ -1396,25 +1403,34 @@ MediaRecorder::NotifyError(nsresult aRv)
if (NS_FAILED(rv)) {
return;
}
nsString errorMsg;
switch (aRv) {
case NS_ERROR_DOM_SECURITY_ERR:
errorMsg = NS_LITERAL_STRING("SecurityError");
break;
case NS_ERROR_OUT_OF_MEMORY:
errorMsg = NS_LITERAL_STRING("OutOfMemoryError");
break;
default:
errorMsg = NS_LITERAL_STRING("GenericError");
}
RecordErrorEventInit init;
MediaRecorderErrorEventInit init;
init.mBubbles = false;
init.mCancelable = false;
init.mName = errorMsg;
// These DOMExceptions have been created earlier so they can contain stack
// traces. We attach the appropriate one here to be fired. We should have
// exceptions here, but defensively check.
switch (aRv) {
case NS_ERROR_DOM_SECURITY_ERR:
if (!mSecurityDomException) {
LOG(LogLevel::Debug, ("MediaRecorder.NotifyError: "
"mSecurityDomException was not initialized"));
mSecurityDomException = DOMException::Create(NS_ERROR_DOM_SECURITY_ERR);
}
init.mError = mSecurityDomException.forget();
break;
default:
if (!mUnknownDomException) {
LOG(LogLevel::Debug, ("MediaRecorder.NotifyError: "
"mUnknownDomException was not initialized"));
mUnknownDomException = DOMException::Create(NS_ERROR_DOM_UNKNOWN_ERR);
}
LOG(LogLevel::Debug, ("MediaRecorder.NotifyError: "
"mUnknownDomException being fired for aRv: %X", uint32_t(aRv)));
init.mError = mUnknownDomException.forget();
}
RefPtr<RecordErrorEvent> event =
RecordErrorEvent::Constructor(this, NS_LITERAL_STRING("error"), init);
RefPtr<MediaRecorderErrorEvent> event = MediaRecorderErrorEvent::Constructor(
this, NS_LITERAL_STRING("error"), init);
event->SetTrusted(true);
bool dummy;
@ -1459,6 +1475,13 @@ MediaRecorder::GetSourceMediaStream()
return mPipeStream ? mPipeStream.get() : mAudioNode->GetStream();
}
void
MediaRecorder::InitializeDomExceptions()
{
mSecurityDomException = DOMException::Create(NS_ERROR_DOM_SECURITY_ERR);
mUnknownDomException = DOMException::Create(NS_ERROR_DOM_UNKNOWN_ERR);
}
size_t
MediaRecorder::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
{

View File

@ -28,6 +28,7 @@ class GlobalObject;
namespace dom {
class AudioNode;
class DOMException;
/**
* Implementation of https://dvcs.w3.org/hg/dap/raw-file/default/media-stream-capture/MediaRecorder.html
@ -133,6 +134,12 @@ protected:
void RemoveSession(Session* aSession);
// Functions for Session to query input source info.
MediaStream* GetSourceMediaStream();
// Create DOMExceptions capturing the JS stack for async errors. These are
// created ahead of time rather than on demand when firing an error as the JS
// stack of the operation that started the async behavior will not be
// available at the time the error event is fired. Note, depending on when
// this is called there may not be a JS stack to capture.
void InitializeDomExceptions();
// DOM wrapper for source media stream. Will be null when input is audio node.
RefPtr<DOMMediaStream> mDOMStream;
// Source audio node. Will be null when input is a media stream.
@ -159,6 +166,12 @@ protected:
uint32_t mVideoBitsPerSecond;
uint32_t mBitsPerSecond;
// DOMExceptions that are created early and possibly thrown in NotifyError.
// Creating them early allows us to capture the JS stack for which cannot be
// done at the time the error event is fired.
RefPtr<DOMException> mSecurityDomException;
RefPtr<DOMException> mUnknownDomException;
private:
// Register MediaRecorder into Document to listen the activity changes.
void RegisterActivityObserver();

View File

@ -21,7 +21,10 @@ function startTest() {
mediaRecorder.onerror = function (e) {
is(callbackStep, 0, 'should fired onstop callback');
is(e.name, 'GenericError', 'error name should be GenericError');
is(e.error.name, 'UnknownError', 'error name should be UnknownError');
ok(e.error.stack.includes('test_mediarecorder_creation_fail.html'),
'Events fired from onerror should include an error with a stack trace indicating ' +
'an error in this test');
is(mediaRecorder.mimeType, '', 'mimetype should be empty');
is(mediaRecorder.state, 'recording', 'state is recording');
info('onerror callback fired');

View File

@ -30,7 +30,7 @@ SpecialPowers.pushPrefEnv({"set": [["media.ogg.enabled", false]]},
//fires again, so set it to null to avoid failures
mediaRecorder.ondataavailable = null;
SimpleTest.finish();
}
};
mediaRecorder.ondataavailable = function(evt) {
ondataavailableFired = true;
ok(evt instanceof BlobEvent,
@ -43,16 +43,21 @@ SpecialPowers.pushPrefEnv({"set": [["media.ogg.enabled", false]]},
'Blob data received should have type = ' + expectedMimeType);
is(evt.target.mimeType, expectedMimeType,
'Mime type in ondataavailable = ' + expectedMimeType);
}
};
mediaRecorder.onerror = function(evt) {
ok(evt instanceof RecordErrorEvent,
'Events fired from onerror should be RecordErrorEvent');
ok(evt instanceof MediaRecorderErrorEvent,
'Events fired from onerror should be MediaRecorderErrorEvent');
is(evt.type, 'error',
'Event type should onerror');
is(evt.name, 'GenericError',
'Event name is GenericError');
'Event type is error');
ok(evt.error instanceof DOMException,
'Events fired from onerror should have a DOMException in their error member');
is(evt.error.name, 'UnknownError', 'Error name should be UnknownError.');
is(evt.error.message, 'The operation failed for an unknown transient reason');
ok(evt.error.stack.includes('test_mediarecorder_getencodeddata.html'),
'Events fired from onerror should include an error with a stack trace indicating ' +
'an error in this test');
onErrorFired = true;
}
};
mediaRecorder.start(0);
is(mediaRecorder.state, 'recording', 'Media recorder should be recording');
is(mediaRecorder.stream, stream,

View File

@ -89,12 +89,17 @@ function testPrincipals(resource) {
hasStopped = new Promise(resolve => rec.onstop = resolve);
video.play();
})
.then(() => ok(true, msgNoThrow), e => is(e.name, null, msgNoThrow))
.then(() => ok(true, msgNoThrow), e => is(e.error.name, null, msgNoThrow))
.then(() => Promise.race([
new Promise((_, reject) => rec.onerror = e => reject(new DOMException("", e.name))),
new Promise((_, reject) => rec.onerror = e => reject(e.error)),
hasEnded
]))
.then(() => ok(false, msgSecErr), e => is(e.name, "SecurityError", msgSecErr))
.then(() => ok(false, msgSecErr), e => {
is(e.name, "SecurityError", msgSecErr);
ok(e.stack.includes('test_mediarecorder_principals.html'),
'Events fired from onerror should include an error with a stack trace indicating ' +
'an error in this test');
})
.then(() => Promise.race([hasStopped, hasEnded.then(() => Promise.reject())]))
.then(() => ok(true, msgOnStop), e => ok(false, msgOnStop))
.then(() => clearInterval(interval));

View File

@ -42,7 +42,10 @@ function startTest() {
}
}
ok(callbackStep < 3, 'onerror callback fired as expected.');
is(e.name, 'GenericError', 'Error name should be GenericError.');
is(e.error.name, 'UnknownError', 'Error name should be UnknownError.');
ok(e.error.stack.includes('test_mediarecorder_unsupported_src.html'),
'Events fired from onerror should include an error with a stack trace indicating ' +
'an error in this test');
is(mediaRecorder.mimeType, '', 'mimetype should be empty');
is(mediaRecorder.state, 'recording', 'state is recording');
info('onerror callback fired');

View File

@ -27,7 +27,7 @@ function on_new_message(event, new_messages) {
}
}
function do_cleanup() {
function* do_cleanup() {
if (webconsole) {
webconsole.ui.off("new-messages", on_new_message);
}

View File

@ -15,15 +15,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=841850
var blankTarget = document.getElementById("blankTarget");
blankTarget.click();
var os = SpecialPowers.Cc["@mozilla.org/observer-service;1"].
getService(SpecialPowers.Components.interfaces.nsIObserverService);
var observer = {
observe: function(subject, topic, data) {
if(topic == "content-document-global-created" && data =="http://example.com") {
parent.parent.postMessage({"test": "blankTarget", "msg": "opened an http link with target=_blank from a secure page"}, "http://mochi.test:8888");
SpecialPowers.removeAsyncObserver(observer, "content-document-global-created");
os.removeObserver(observer, "content-document-global-created");
}
}
}
SpecialPowers.addAsyncObserver(observer, "content-document-global-created");
os.addObserver(observer, "content-document-global-created");
</script>
</body>

View File

@ -8,6 +8,8 @@
// NOTE: This js file requires db_smilCSSPropertyList.js
const isServoEnabled = SpecialPowers.DOMWindowUtils.isStyledByServo;
// Lists of testcases for re-use across multiple properties of the same type
var _fromByTestLists =
{
@ -24,17 +26,30 @@ var _fromByTestLists =
{ midComp: "rgba(45, 48, 52, 0.6)",
// (rgb(10, 20, 30) * 0.2 + rgb(50, 50, 50) * 1) / 1.0
toComp: "rgb(52, 54, 56)"}),
// Note: technically, the "from" and "by" values in the test case below
// would overflow the maxium color-channel values when added together.
// The "from" and "by" values in the test case below overflow the maxium
// color-channel values when added together.
// (e.g. for red [ignoring alpha for now], 100 + 240 = 340 which is > 255)
// The SVG Animation spec says we should clamp color values "as late as
// possible," i.e. allow the channel overflow and clamp at paint-time.
// But for now, we instead clamp the implicit "to" value for the animation
// and interpolate up to that clamped result.
// possible" i.e. allow the channel overflow and clamp at paint-time.
//
// Servo does this, and gives us:
//
// to-value = (rgb(100, 100, 100) * 0.6 + rgb(240, 240, 240) * 1.0)) * 1
// = rgb(300, 300, 300)
// midComp = (rgb(100, 100, 100) * 0.6 * 0.5 + rgb(300, 300, 300) * 1.0 * 0.5) * (1 / 0.8)
// = rgb(225, 225, 225)
//
// Gecko, however, clamps the "to" value and interpolates up to that
// clamped result giving:
//
// midComp = (rgb(100, 100, 100) * 0.6 * 0.5 + rgb(255, 255, 255) * 1.0 * 0.5) * (1 / 0.8)
// = rgb(197, 197, 197)
//
new AnimTestcaseFromBy("rgba(100, 100, 100, 0.6)", "rgba(240, 240, 240, 1)",
// (rgb(100, 100, 100) * 0.6 * 0.5 + rgb(255, 255, 255) * 1.0 * 0.5) * (1 / 0.8)
{ midComp: "rgba(197, 197, 197, 0.8)",
// (rgb(100, 100, 100) * 0.6 + rgb(240, 240, 240) is overflowed
{ midComp:
isServoEnabled ? "rgba(225, 225, 225, 0.8)"
: "rgba(197, 197, 197, 0.8)",
toComp: "rgb(255, 255, 255)"}),
],
lengthNoUnits: [

View File

@ -640,6 +640,8 @@ var interfaceNamesInGlobalScope =
"MediaQueryListEvent",
// IMPORTANT: Do not change this list without review from a DOM peer!
"MediaRecorder",
// IMPORTANT: Do not change this list without review from a DOM peer!
"MediaRecorderErrorEvent",
// IMPORTANT: Do not change this list without review from a DOM peer!
"MediaSource",
// IMPORTANT: Do not change this list without review from a DOM peer!
@ -786,8 +788,6 @@ var interfaceNamesInGlobalScope =
"RadioNodeList",
// IMPORTANT: Do not change this list without review from a DOM peer!
"Range",
// IMPORTANT: Do not change this list without review from a DOM peer!
"RecordErrorEvent",
// IMPORTANT: Do not change this list without review from a DOM peer!
"Rect",
// IMPORTANT: Do not change this list without review from a DOM peer!

View File

@ -0,0 +1,21 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/.
*
* The origin of this IDL file is
* https://w3c.github.io/mediacapture-record/
*
* Copyright © 2017 W3C® (MIT, ERCIM, Keio, Beihang). W3C liability, trademark
* and document use rules apply.
*/
dictionary MediaRecorderErrorEventInit : EventInit {
required DOMException error;
};
[Exposed=Window,
Constructor(DOMString type, MediaRecorderErrorEventInit eventInitDict)]
interface MediaRecorderErrorEvent : Event {
[SameObject] readonly attribute DOMException error;
};

View File

@ -1,16 +0,0 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/.
*/
[Constructor(DOMString type, optional RecordErrorEventInit eventInitDict)]
interface RecordErrorEvent : Event
{
readonly attribute DOMString name;
};
dictionary RecordErrorEventInit : EventInit
{
DOMString name = "";
};

View File

@ -1031,7 +1031,6 @@ WEBIDL_FILES += [
'PopStateEvent.webidl',
'PopupBlockedEvent.webidl',
'ProgressEvent.webidl',
'RecordErrorEvent.webidl',
'StyleRuleChangeEvent.webidl',
'StyleSheetApplicableStateChangeEvent.webidl',
'StyleSheetChangeEvent.webidl',
@ -1079,6 +1078,7 @@ GENERATED_EVENTS_WEBIDL_FILES = [
'HiddenPluginEvent.webidl',
'ImageCaptureErrorEvent.webidl',
'MediaQueryListEvent.webidl',
'MediaRecorderErrorEvent.webidl',
'MediaStreamEvent.webidl',
'MediaStreamTrackEvent.webidl',
'OfflineAudioCompletionEvent.webidl',
@ -1091,7 +1091,6 @@ GENERATED_EVENTS_WEBIDL_FILES = [
'PresentationConnectionCloseEvent.webidl',
'ProgressEvent.webidl',
'PromiseRejectionEvent.webidl',
'RecordErrorEvent.webidl',
'ScrollViewChangeEvent.webidl',
'StyleRuleChangeEvent.webidl',
'StyleSheetApplicableStateChangeEvent.webidl',

View File

@ -2020,7 +2020,7 @@ RuntimeService::Init()
if (!sDefaultJSSettings.gcSettings[0].IsSet()) {
sDefaultJSSettings.contextOptions = JS::ContextOptions();
sDefaultJSSettings.chrome.maxScriptRuntime = -1;
sDefaultJSSettings.chrome.compartmentOptions.behaviors().setVersion(JSVERSION_LATEST);
sDefaultJSSettings.chrome.compartmentOptions.behaviors().setVersion(JSVERSION_DEFAULT);
sDefaultJSSettings.content.maxScriptRuntime = MAX_SCRIPT_RUN_TIME_SEC;
#ifdef JS_GC_ZEAL
sDefaultJSSettings.gcZealFrequency = JS_DEFAULT_ZEAL_FREQ;

View File

@ -1961,7 +1961,7 @@ ScriptExecutorRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
.setNoScriptRval(true);
if (mScriptLoader.mWorkerScriptType == DebuggerScript) {
options.setVersion(JSVERSION_LATEST);
options.setVersion(JSVERSION_DEFAULT);
}
MOZ_ASSERT(loadInfo.mMutedErrorFlag.isSome());

View File

@ -41,7 +41,6 @@ add_task(function setupPrefs() {
return SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true],
["browser.newtab.preload", false],
]});
});

View File

@ -226,18 +226,15 @@ nsXBLDocumentInfo::ReadPrototypeBindings(nsIURI* aURI, nsXBLDocumentInfo** aDocI
nsContentUtils::GetSecurityManager()->
GetSystemPrincipal(getter_AddRefs(principal));
auto styleBackend = aBoundDocument ? aBoundDocument->GetStyleBackendType()
: StyleBackendType::Gecko;
nsCOMPtr<nsIDOMDocument> domdoc;
rv = NS_NewXBLDocument(getter_AddRefs(domdoc), aURI, nullptr, principal);
rv = NS_NewXBLDocument(getter_AddRefs(domdoc), aURI, nullptr, principal, styleBackend);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domdoc);
NS_ASSERTION(doc, "Must have a document!");
// Set the style backend type immediately after creating the XBL document.
// Assume gecko if there's no bound document.
doc->SetStyleBackendType(aBoundDocument ? aBoundDocument->GetStyleBackendType()
: StyleBackendType::Gecko);
RefPtr<nsXBLDocumentInfo> docInfo = new nsXBLDocumentInfo(doc);
while (1) {

View File

@ -434,7 +434,7 @@ nsXBLProtoImplField::InstallField(JS::Handle<JSObject*> aBoundNode,
JS::Rooted<JS::Value> result(cx);
JS::CompileOptions options(cx);
options.setFileAndLine(uriSpec.get(), mLineNumber)
.setVersion(JSVERSION_LATEST);
.setVersion(JSVERSION_DEFAULT);
JS::AutoObjectVector scopeChain(cx);
if (!nsJSUtils::GetScopeChainForElement(cx, boundElement, scopeChain)) {
return NS_ERROR_OUT_OF_MEMORY;

View File

@ -193,7 +193,7 @@ nsXBLProtoImplMethod::CompileMember(AutoJSAPI& jsapi, const nsString& aClassStr,
JS::CompileOptions options(cx);
options.setFileAndLine(functionUri.get(),
uncompiledMethod->mBodyText.GetLineNumber())
.setVersion(JSVERSION_LATEST);
.setVersion(JSVERSION_DEFAULT);
JS::Rooted<JSObject*> methodObject(cx);
JS::AutoObjectVector emptyVector(cx);
nsresult rv = nsJSUtils::CompileFunction(jsapi, emptyVector, options, cname,

View File

@ -199,7 +199,7 @@ nsXBLProtoImplProperty::CompileMember(AutoJSAPI& jsapi, const nsString& aClassSt
JSAutoCompartment ac(cx, aClassObject);
JS::CompileOptions options(cx);
options.setFileAndLine(functionUri.get(), getterText->GetLineNumber())
.setVersion(JSVERSION_LATEST);
.setVersion(JSVERSION_DEFAULT);
nsCString name = NS_LITERAL_CSTRING("get_") + NS_ConvertUTF16toUTF8(mName);
JS::Rooted<JSObject*> getterObject(cx);
JS::AutoObjectVector emptyVector(cx);
@ -245,7 +245,7 @@ nsXBLProtoImplProperty::CompileMember(AutoJSAPI& jsapi, const nsString& aClassSt
JSAutoCompartment ac(cx, aClassObject);
JS::CompileOptions options(cx);
options.setFileAndLine(functionUri.get(), setterText->GetLineNumber())
.setVersion(JSVERSION_LATEST);
.setVersion(JSVERSION_DEFAULT);
nsCString name = NS_LITERAL_CSTRING("set_") + NS_ConvertUTF16toUTF8(mName);
JS::Rooted<JSObject*> setterObject(cx);
JS::AutoObjectVector emptyVector(cx);

View File

@ -435,7 +435,7 @@ nsXBLPrototypeHandler::EnsureEventHandler(AutoJSAPI& jsapi, nsIAtom* aName,
JSAutoCompartment ac(cx, scopeObject);
JS::CompileOptions options(cx);
options.setFileAndLine(bindingURI.get(), mLineNumber)
.setVersion(JSVERSION_LATEST);
.setVersion(JSVERSION_DEFAULT);
JS::Rooted<JSObject*> handlerFun(cx);
JS::AutoObjectVector emptyVector(cx);

View File

@ -186,6 +186,7 @@ XMLHttpRequestMainThread::XMLHttpRequestMainThread()
mResponseType(XMLHttpRequestResponseType::_empty),
mRequestObserver(nullptr),
mState(State::unsent),
mStyleBackend(StyleBackendType::None),
mFlagSynchronous(false), mFlagAborted(false), mFlagParseBody(false),
mFlagSyncLooping(false), mFlagBackgroundRequest(false),
mFlagHadUploadListenersOnSend(false), mFlagACwithCredentials(false),
@ -2162,7 +2163,8 @@ XMLHttpRequestMainThread::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
emptyStr, emptyStr, nullptr, docURI,
baseURI, requestingPrincipal, true, global,
mIsHtml ? DocumentFlavorHTML :
DocumentFlavorLegacyGuess);
DocumentFlavorLegacyGuess,
mStyleBackend);
NS_ENSURE_SUCCESS(rv, rv);
mResponseXML = do_QueryInterface(responseDoc);
mResponseXML->SetChromeXHRDocURI(chromeXHRDocURI);

View File

@ -200,8 +200,13 @@ public:
nsILoadGroup* aLoadGroup = nullptr)
{
MOZ_ASSERT(aPrincipal);
MOZ_ASSERT_IF(nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(
aGlobalObject), win->IsInnerWindow());
nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(aGlobalObject);
if (win) {
MOZ_ASSERT(win->IsInnerWindow());
if (win->GetExtantDoc()) {
mStyleBackend = win->GetExtantDoc()->GetStyleBackendType();
}
}
mPrincipal = aPrincipal;
BindToOwner(aGlobalObject);
mBaseURI = aBaseURI;
@ -743,6 +748,8 @@ protected:
State mState;
StyleBackendType mStyleBackend;
bool mFlagSynchronous;
bool mFlagAborted;
bool mFlagParseBody;

View File

@ -69,7 +69,8 @@ NS_NewDOMDocument(nsIDOMDocument** aInstancePtrResult,
nsIPrincipal* aPrincipal,
bool aLoadedAsData,
nsIGlobalObject* aEventObject,
DocumentFlavor aFlavor)
DocumentFlavor aFlavor,
StyleBackendType aStyleBackend)
{
// Note: can't require that aDocumentURI/aBaseURI/aPrincipal be non-null,
// since at least one caller (XMLHttpRequest) doesn't have decent args to
@ -128,6 +129,12 @@ NS_NewDOMDocument(nsIDOMDocument** aInstancePtrResult,
return rv;
}
// If we were passed an explicit style backend for this document set it
// immediately after creation, before any content is inserted.
if (aStyleBackend != StyleBackendType::None) {
d->SetStyleBackendType(aStyleBackend);
}
if (isHTML) {
nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(d);
NS_ASSERTION(htmlDoc, "HTML Document doesn't implement nsIHTMLDocument?");
@ -209,13 +216,15 @@ nsresult
NS_NewXBLDocument(nsIDOMDocument** aInstancePtrResult,
nsIURI* aDocumentURI,
nsIURI* aBaseURI,
nsIPrincipal* aPrincipal)
nsIPrincipal* aPrincipal,
StyleBackendType aStyleBackend)
{
nsresult rv = NS_NewDOMDocument(aInstancePtrResult,
NS_LITERAL_STRING("http://www.mozilla.org/xbl"),
NS_LITERAL_STRING("bindings"), nullptr,
aDocumentURI, aBaseURI, aPrincipal, false,
nullptr, DocumentFlavorLegacyGuess);
nullptr, DocumentFlavorLegacyGuess,
aStyleBackend);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocument> idoc = do_QueryInterface(*aInstancePtrResult);

View File

@ -835,7 +835,7 @@ XULContentSinkImpl::OpenScript(const char16_t** aAttributes,
const uint32_t aLineNumber)
{
bool isJavaScript = true;
uint32_t version = JSVERSION_LATEST;
uint32_t version = JSVERSION_DEFAULT;
nsresult rv;
// Look for SRC attribute and look for a LANGUAGE attribute
@ -861,14 +861,14 @@ XULContentSinkImpl::OpenScript(const char16_t** aAttributes,
if (nsContentUtils::IsJavascriptMIMEType(mimeType)) {
isJavaScript = true;
version = JSVERSION_LATEST;
version = JSVERSION_DEFAULT;
// Get the version string, and ensure that JavaScript supports it.
nsAutoString versionName;
rv = parser.GetParameter("version", versionName);
if (NS_SUCCEEDED(rv)) {
version = nsContentUtils::ParseJavascriptVersion(versionName);
version = JSVERSION_UNKNOWN;
} else if (rv != NS_ERROR_INVALID_ARG) {
return rv;
}

View File

@ -232,16 +232,9 @@ nsSetDocumentStateCommand::DoCommandParams(const char *aCommandName,
bool isReadOnly;
nsresult rvRO = aParams->GetBooleanValue(STATE_ATTRIBUTE, &isReadOnly);
NS_ENSURE_SUCCESS(rvRO, rvRO);
uint32_t flags;
textEditor->GetFlags(&flags);
if (isReadOnly) {
flags |= nsIPlaintextEditor::eEditorReadonlyMask;
} else {
flags &= ~(nsIPlaintextEditor::eEditorReadonlyMask);
}
return textEditor->SetFlags(flags);
return isReadOnly ?
textEditor->AddFlags(nsIPlaintextEditor::eEditorReadonlyMask) :
textEditor->RemoveFlags(nsIPlaintextEditor::eEditorReadonlyMask);
}
if (!nsCRT::strcmp(aCommandName, "cmd_setDocumentUseCSS")) {

View File

@ -956,16 +956,8 @@ EditorBase::EndTransaction()
return NS_OK;
}
// These two routines are similar to the above, but do not use
// the transaction managers batching feature. Instead we use
// a placeholder transaction to wrap up any further transaction
// while the batch is open. The advantage of this is that
// placeholder transactions can later merge, if needed. Merging
// is unavailable between transaction manager batches.
NS_IMETHODIMP
EditorBase::BeginPlaceHolderTransaction(nsIAtom* aName)
void
EditorBase::BeginPlaceholderTransaction(nsIAtom* aTransactionName)
{
MOZ_ASSERT(mPlaceholderBatch >= 0, "negative placeholder batch count!");
if (!mPlaceholderBatch) {
@ -973,7 +965,7 @@ EditorBase::BeginPlaceHolderTransaction(nsIAtom* aName)
// time to turn on the batch
BeginUpdateViewBatch();
mPlaceholderTransaction = nullptr;
mPlaceholderName = aName;
mPlaceholderName = aTransactionName;
RefPtr<Selection> selection = GetSelection();
if (selection) {
mSelState.emplace();
@ -989,12 +981,10 @@ EditorBase::BeginPlaceHolderTransaction(nsIAtom* aName)
}
}
mPlaceholderBatch++;
return NS_OK;
}
NS_IMETHODIMP
EditorBase::EndPlaceHolderTransaction()
void
EditorBase::EndPlaceholderTransaction()
{
MOZ_ASSERT(mPlaceholderBatch > 0,
"zero or negative placeholder batch count when ending batch!");
@ -1057,8 +1047,6 @@ EditorBase::EndPlaceHolderTransaction()
}
}
mPlaceholderBatch--;
return NS_OK;
}
NS_IMETHODIMP
@ -1335,10 +1323,9 @@ EditorBase::RemoveAttribute(Element* aElement,
bool
EditorBase::OutputsMozDirty()
{
// Return true for Composer (!eEditorAllowInteraction) or mail
// (eEditorMailMask), but false for webpages.
return !(mFlags & nsIPlaintextEditor::eEditorAllowInteraction) ||
(mFlags & nsIPlaintextEditor::eEditorMailMask);
// Return true for Composer (!IsInteractionAllowed()) or mail
// (IsMailEditor()), but false for webpages.
return !IsInteractionAllowed() || IsMailEditor();
}
NS_IMETHODIMP
@ -2193,11 +2180,13 @@ EditorBase::EndIMEComposition()
NS_IMETHODIMP
EditorBase::ForceCompositionEnd()
{
nsCOMPtr<nsIPresShell> ps = GetPresShell();
if (!ps) {
return NS_ERROR_NOT_AVAILABLE;
}
nsPresContext* pc = ps->GetPresContext();
return CommitComposition();
}
nsresult
EditorBase::CommitComposition()
{
nsPresContext* pc = GetPresContext();
if (!pc) {
return NS_ERROR_NOT_AVAILABLE;
}
@ -2342,7 +2331,7 @@ EditorBase::CloneAttributes(Element* aDest,
{
MOZ_ASSERT(aDest && aSource);
AutoEditBatch beginBatching(this);
AutoPlaceholderBatch beginBatching(this);
// Use transaction system for undo only if destination is already in the
// document
@ -5002,8 +4991,7 @@ EditorBase::DetermineCurrentDirection()
// If we don't have an explicit direction, determine our direction
// from the content's direction
if (!(mFlags & (nsIPlaintextEditor::eEditorLeftToRight |
nsIPlaintextEditor::eEditorRightToLeft))) {
if (!IsRightToLeft() && !IsLeftToRight()) {
nsIFrame* frame = rootElement->GetPrimaryFrame();
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
@ -5029,14 +5017,14 @@ EditorBase::SwitchTextDirection()
NS_ENSURE_SUCCESS(rv, rv);
// Apply the opposite direction
if (mFlags & nsIPlaintextEditor::eEditorRightToLeft) {
NS_ASSERTION(!(mFlags & nsIPlaintextEditor::eEditorLeftToRight),
if (IsRightToLeft()) {
NS_ASSERTION(!IsLeftToRight(),
"Unexpected mutually exclusive flag");
mFlags &= ~nsIPlaintextEditor::eEditorRightToLeft;
mFlags |= nsIPlaintextEditor::eEditorLeftToRight;
rv = rootElement->SetAttr(kNameSpaceID_None, nsGkAtoms::dir, NS_LITERAL_STRING("ltr"), true);
} else if (mFlags & nsIPlaintextEditor::eEditorLeftToRight) {
NS_ASSERTION(!(mFlags & nsIPlaintextEditor::eEditorRightToLeft),
} else if (IsLeftToRight()) {
NS_ASSERTION(!IsRightToLeft(),
"Unexpected mutually exclusive flag");
mFlags |= nsIPlaintextEditor::eEditorRightToLeft;
mFlags &= ~nsIPlaintextEditor::eEditorLeftToRight;
@ -5061,14 +5049,14 @@ EditorBase::SwitchTextDirectionTo(uint32_t aDirection)
// Apply the requested direction
if (aDirection == nsIPlaintextEditor::eEditorLeftToRight &&
(mFlags & nsIPlaintextEditor::eEditorRightToLeft)) {
IsRightToLeft()) {
NS_ASSERTION(!(mFlags & nsIPlaintextEditor::eEditorLeftToRight),
"Unexpected mutually exclusive flag");
mFlags &= ~nsIPlaintextEditor::eEditorRightToLeft;
mFlags |= nsIPlaintextEditor::eEditorLeftToRight;
rv = rootElement->SetAttr(kNameSpaceID_None, nsGkAtoms::dir, NS_LITERAL_STRING("ltr"), true);
} else if (aDirection == nsIPlaintextEditor::eEditorRightToLeft &&
(mFlags & nsIPlaintextEditor::eEditorLeftToRight)) {
IsLeftToRight()) {
NS_ASSERTION(!(mFlags & nsIPlaintextEditor::eEditorRightToLeft),
"Unexpected mutually exclusive flag");
mFlags |= nsIPlaintextEditor::eEditorRightToLeft;

View File

@ -251,6 +251,11 @@ public:
already_AddRefed<nsIDOMDocument> GetDOMDocument();
already_AddRefed<nsIDocument> GetDocument();
already_AddRefed<nsIPresShell> GetPresShell();
nsPresContext* GetPresContext()
{
RefPtr<nsIPresShell> presShell = GetPresShell();
return presShell ? presShell->GetPresContext() : nullptr;
}
already_AddRefed<nsIWidget> GetWidget();
nsISelectionController* GetSelectionController() const
{
@ -351,6 +356,15 @@ public:
WidgetCompositionEvent* aCompositionChangeEvet) = 0;
void EndIMEComposition();
/**
* Commit composition if there is.
* Note that when there is a composition, this requests to commit composition
* to native IME. Therefore, when there is composition, this can do anything.
* For example, the editor instance, the widget or the process itself may
* be destroyed.
*/
nsresult CommitComposition();
void SwitchTextDirectionTo(uint32_t aDirection);
protected:
@ -580,6 +594,18 @@ protected:
nsresult GetSelection(SelectionType aSelectionType,
nsISelection** aSelection);
/**
* (Begin|End)PlaceholderTransaction() are called by AutoPlaceholderBatch.
* This set of methods are similar to the (Begin|End)Transaction(), but do
* not use the transaction managers batching feature. Instead we use a
* placeholder transaction to wrap up any further transaction while the
* batch is open. The advantage of this is that placeholder transactions
* can later merge, if needed. Merging is unavailable between transaction
* manager batches.
*/
void BeginPlaceholderTransaction(nsIAtom* aTransactionName);
void EndPlaceholderTransaction();
public:
/**
* All editor operations which alter the doc should be prefaced
@ -947,6 +973,36 @@ public:
*/
uint32_t Flags() const { return mFlags; }
nsresult AddFlags(uint32_t aFlags)
{
const uint32_t kOldFlags = Flags();
const uint32_t kNewFlags = (kOldFlags | aFlags);
if (kNewFlags == kOldFlags) {
return NS_OK;
}
return SetFlags(kNewFlags); // virtual call and may be expensive.
}
nsresult RemoveFlags(uint32_t aFlags)
{
const uint32_t kOldFlags = Flags();
const uint32_t kNewFlags = (kOldFlags & ~aFlags);
if (kNewFlags == kOldFlags) {
return NS_OK;
}
return SetFlags(kNewFlags); // virtual call and may be expensive.
}
nsresult AddAndRemoveFlags(uint32_t aAddingFlags, uint32_t aRemovingFlags)
{
MOZ_ASSERT(!(aAddingFlags & aRemovingFlags),
"Same flags are specified both adding and removing");
const uint32_t kOldFlags = Flags();
const uint32_t kNewFlags = ((kOldFlags | aAddingFlags) & ~aRemovingFlags);
if (kNewFlags == kOldFlags) {
return NS_OK;
}
return SetFlags(kNewFlags); // virtual call and may be expensive.
}
bool IsPlaintextEditor() const
{
return (mFlags & nsIPlaintextEditor::eEditorPlaintextMask) != 0;
@ -1250,6 +1306,7 @@ protected:
bool mIsHTMLEditorClass;
friend bool NSCanUnload(nsISupports* serviceMgr);
friend class AutoPlaceholderBatch;
friend class AutoRules;
friend class AutoSelectionRestorer;
friend class AutoTransactionsConserveSelection;

View File

@ -12,6 +12,7 @@
#include "mozilla/EventListenerManager.h" // for EventListenerManager
#include "mozilla/IMEStateManager.h" // for IMEStateManager
#include "mozilla/Preferences.h" // for Preferences
#include "mozilla/TextEditor.h" // for TextEditor
#include "mozilla/TextEvents.h" // for WidgetCompositionEvent
#include "mozilla/dom/Element.h" // for Element
#include "mozilla/dom/Event.h" // for Event
@ -36,11 +37,8 @@
#include "nsIDOMMouseEvent.h" // for nsIDOMMouseEvent
#include "nsIDOMNode.h" // for nsIDOMNode
#include "nsIDocument.h" // for nsIDocument
#include "nsIEditor.h" // for EditorBase::GetSelection, etc.
#include "nsIEditorMailSupport.h" // for nsIEditorMailSupport
#include "nsIFocusManager.h" // for nsIFocusManager
#include "nsIFormControl.h" // for nsIFormControl, etc.
#include "nsIHTMLEditor.h" // for nsIHTMLEditor
#include "nsINode.h" // for nsINode, ::NODE_IS_EDITABLE, etc.
#include "nsIPlaintextEditor.h" // for nsIPlaintextEditor, etc.
#include "nsIPresShell.h" // for nsIPresShell
@ -366,7 +364,7 @@ EditorEventListener::EnsureCommitCompoisition()
{
MOZ_ASSERT(!DetachedFromEditor());
RefPtr<EditorBase> editorBase(mEditorBase);
editorBase->ForceCompositionEnd();
editorBase->CommitComposition();
return !DetachedFromEditor();
}
@ -711,19 +709,14 @@ EditorEventListener::HandleMiddleClickPaste(nsIDOMMouseEvent* aMouseEvent)
return NS_ERROR_NULL_POINTER;
}
RefPtr<EditorBase> editorBase(mEditorBase);
RefPtr<Selection> selection = editorBase->GetSelection();
RefPtr<TextEditor> textEditor = mEditorBase->AsTextEditor();
MOZ_ASSERT(textEditor);
RefPtr<Selection> selection = textEditor->GetSelection();
if (selection) {
selection->Collapse(parent, offset);
}
// If the ctrl key is pressed, we'll do paste as quotation.
// Would've used the alt key, but the kde wmgr treats alt-middle specially.
nsCOMPtr<nsIEditorMailSupport> mailEditor;
if (clickEvent->IsControl()) {
mailEditor = do_QueryObject(editorBase);
}
nsresult rv;
int32_t clipboard = nsIClipboard::kGlobalClipboard;
nsCOMPtr<nsIClipboard> clipboardService =
@ -736,10 +729,12 @@ EditorEventListener::HandleMiddleClickPaste(nsIDOMMouseEvent* aMouseEvent)
}
}
if (mailEditor) {
mailEditor->PasteAsQuotation(clipboard);
// If the ctrl key is pressed, we'll do paste as quotation.
// Would've used the alt key, but the kde wmgr treats alt-middle specially.
if (clickEvent->IsControl()) {
textEditor->PasteAsQuotation(clipboard);
} else {
editorBase->Paste(clipboard);
textEditor->Paste(clipboard);
}
// Prevent the event from propagating up to be possibly handled
@ -1191,11 +1186,8 @@ EditorEventListener::SpellCheckIfNeeded()
// If the spell check skip flag is still enabled from creation time,
// disable it because focused editors are allowed to spell check.
RefPtr<EditorBase> editorBase(mEditorBase);
uint32_t currentFlags = 0;
editorBase->GetFlags(&currentFlags);
if(currentFlags & nsIPlaintextEditor::eEditorSkipSpellCheck) {
currentFlags ^= nsIPlaintextEditor::eEditorSkipSpellCheck;
editorBase->SetFlags(currentFlags);
if(editorBase->ShouldSkipSpellCheck()) {
editorBase->RemoveFlags(nsIPlaintextEditor::eEditorSkipSpellCheck);
}
}

View File

@ -143,52 +143,43 @@ EditActionCanceled(nsresult aRv = NS_OK)
/***************************************************************************
* stack based helper class for batching a collection of transactions inside a
* placeholder transaction.
* XXX This is used by mozInlineSpellChecker. Therefore, cannot use concrete
* editor class.
*/
class MOZ_RAII AutoPlaceHolderBatch
class MOZ_RAII AutoPlaceholderBatch final
{
private:
nsCOMPtr<nsIEditor> mEditor;
RefPtr<EditorBase> mEditorBase;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
public:
AutoPlaceHolderBatch(nsIEditor* aEditor,
nsIAtom* aAtom
explicit AutoPlaceholderBatch(EditorBase* aEditorBase
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mEditorBase(aEditorBase)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
BeginPlaceholderTransaction(nullptr);
}
AutoPlaceholderBatch(EditorBase* aEditorBase,
nsIAtom* aTransactionName
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mEditor(aEditor)
: mEditorBase(aEditorBase)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
if (mEditor) {
mEditor->BeginPlaceHolderTransaction(aAtom);
}
BeginPlaceholderTransaction(aTransactionName);
}
~AutoPlaceHolderBatch()
~AutoPlaceholderBatch()
{
if (mEditor) {
mEditor->EndPlaceHolderTransaction();
if (mEditorBase) {
mEditorBase->EndPlaceholderTransaction();
}
}
};
/***************************************************************************
* stack based helper class for batching a collection of txns.
* Note: I changed this to use placeholder batching so that we get
* proper selection save/restore across undo/redo.
*/
class MOZ_RAII AutoEditBatch final : public AutoPlaceHolderBatch
{
private:
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
public:
explicit AutoEditBatch(nsIEditor* aEditor
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: AutoPlaceHolderBatch(aEditor, nullptr)
void BeginPlaceholderTransaction(nsIAtom* aTransactionName)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
if (mEditorBase) {
mEditorBase->BeginPlaceholderTransaction(aTransactionName);
}
}
~AutoEditBatch() {}
};
/***************************************************************************

View File

@ -53,7 +53,7 @@ using namespace dom;
NS_IMETHODIMP
HTMLEditor::AbsolutePositionSelection(bool aEnabled)
{
AutoEditBatch beginBatching(this);
AutoPlaceholderBatch beginBatching(this);
AutoRules beginRulesSniffing(this,
aEnabled ? EditAction::setAbsolutePosition :
EditAction::removeAbsolutePosition,
@ -180,7 +180,7 @@ HTMLEditor::SetElementZIndex(nsIDOMElement* aElement,
NS_IMETHODIMP
HTMLEditor::RelativeChangeZIndex(int32_t aChange)
{
AutoEditBatch beginBatching(this);
AutoPlaceholderBatch beginBatching(this);
AutoRules beginRulesSniffing(this,
(aChange < 0) ? EditAction::decreaseZIndex :
EditAction::increaseZIndex,
@ -466,7 +466,7 @@ HTMLEditor::SetFinalPosition(int32_t aX,
y.AppendInt(newY);
// we want one transaction only from a user's point of view
AutoEditBatch batchIt(this);
AutoPlaceholderBatch batchIt(this);
nsCOMPtr<Element> absolutelyPositionedObject =
do_QueryInterface(mAbsolutelyPositionedObject);
@ -510,7 +510,7 @@ HTMLEditor::AbsolutelyPositionElement(nsIDOMElement* aElement,
if (isPositioned == aEnabled)
return NS_OK;
AutoEditBatch batchIt(this);
AutoPlaceholderBatch batchIt(this);
if (aEnabled) {
int32_t x, y;
@ -613,7 +613,7 @@ HTMLEditor::SetElementPosition(Element& aElement,
int32_t aX,
int32_t aY)
{
AutoEditBatch batchIt(this);
AutoPlaceholderBatch batchIt(this);
mCSSEditUtils->SetCSSPropertyPixels(aElement, *nsGkAtoms::left, aX);
mCSSEditUtils->SetCSSPropertyPixels(aElement, *nsGkAtoms::top, aY);
}

View File

@ -1016,7 +1016,7 @@ HTMLEditor::TypedText(const nsAString& aString,
{
MOZ_ASSERT(!aString.IsEmpty() || aAction != eTypedText);
AutoPlaceHolderBatch batch(this, nsGkAtoms::TypingTxnName);
AutoPlaceholderBatch batch(this, nsGkAtoms::TypingTxnName);
if (aAction == eTypedBR) {
// only inserts a br node
@ -1203,7 +1203,7 @@ HTMLEditor::ReplaceHeadContentsWithHTML(const nsAString& aSourceToInsert)
RefPtr<Selection> selection = GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
ForceCompositionEnd();
CommitComposition();
// Do not use AutoRules -- rules code won't let us insert in <head>. Use
// the head node as a parent and delete/insert directly.
@ -1230,7 +1230,7 @@ HTMLEditor::ReplaceHeadContentsWithHTML(const nsAString& aSourceToInsert)
// Mac linebreaks: Map any remaining CR to LF:
inputString.ReplaceSubstring(u"\r", u"\n");
AutoEditBatch beginBatching(this);
AutoPlaceholderBatch beginBatching(this);
// Get the first range in the selection, for context:
RefPtr<nsRange> range = selection->GetRangeAt(0);
@ -1273,7 +1273,7 @@ HTMLEditor::ReplaceHeadContentsWithHTML(const nsAString& aSourceToInsert)
NS_IMETHODIMP
HTMLEditor::RebuildDocumentFromSource(const nsAString& aSourceString)
{
ForceCompositionEnd();
CommitComposition();
RefPtr<Selection> selection = GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
@ -1318,7 +1318,7 @@ HTMLEditor::RebuildDocumentFromSource(const nsAString& aSourceString)
}
// Time to change the document
AutoEditBatch beginBatching(this);
AutoPlaceholderBatch beginBatching(this);
nsReadingIterator<char16_t> endtotal;
aSourceString.EndReading(endtotal);
@ -1537,8 +1537,8 @@ HTMLEditor::InsertElementAtSelection(nsIDOMElement* aElement,
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aElement);
ForceCompositionEnd();
AutoEditBatch beginBatching(this);
CommitComposition();
AutoPlaceholderBatch beginBatching(this);
AutoRules beginRulesSniffing(this, EditAction::insertElement,
nsIEditor::eNext);
@ -1997,7 +1997,7 @@ HTMLEditor::MakeOrChangeList(const nsAString& aListType,
bool cancel, handled;
AutoEditBatch beginBatching(this);
AutoPlaceholderBatch beginBatching(this);
AutoRules beginRulesSniffing(this, EditAction::makeList, nsIEditor::eNext);
// pre-process
@ -2068,7 +2068,7 @@ HTMLEditor::RemoveList(const nsAString& aListType)
bool cancel, handled;
AutoEditBatch beginBatching(this);
AutoPlaceholderBatch beginBatching(this);
AutoRules beginRulesSniffing(this, EditAction::removeList, nsIEditor::eNext);
// pre-process
@ -2103,7 +2103,7 @@ HTMLEditor::MakeDefinitionItem(const nsAString& aItemType)
bool cancel, handled;
AutoEditBatch beginBatching(this);
AutoPlaceholderBatch beginBatching(this);
AutoRules beginRulesSniffing(this, EditAction::makeDefListItem,
nsIEditor::eNext);
@ -2136,7 +2136,7 @@ HTMLEditor::InsertBasicBlock(const nsAString& aBlockType)
bool cancel, handled;
AutoEditBatch beginBatching(this);
AutoPlaceholderBatch beginBatching(this);
AutoRules beginRulesSniffing(this, EditAction::makeBasicBlock,
nsIEditor::eNext);
@ -2208,7 +2208,7 @@ HTMLEditor::Indent(const nsAString& aIndent)
if (aIndent.LowerCaseEqualsLiteral("outdent")) {
opID = EditAction::outdent;
}
AutoEditBatch beginBatching(this);
AutoPlaceholderBatch beginBatching(this);
AutoRules beginRulesSniffing(this, opID, nsIEditor::eNext);
// pre-process
@ -2277,7 +2277,7 @@ HTMLEditor::Align(const nsAString& aAlignType)
// Protect the edit rules object from dying
nsCOMPtr<nsIEditRules> rules(mRules);
AutoEditBatch beginBatching(this);
AutoPlaceholderBatch beginBatching(this);
AutoRules beginRulesSniffing(this, EditAction::align, nsIEditor::eNext);
bool cancel, handled;
@ -2689,7 +2689,7 @@ HTMLEditor::InsertLinkAroundSelection(nsIDOMElement* aAnchorElement)
return NS_OK;
}
AutoEditBatch beginBatching(this);
AutoPlaceholderBatch beginBatching(this);
// Set all attributes found on the supplied anchor element
nsCOMPtr<nsIDOMMozNamedAttrMap> attrMap;
@ -3272,7 +3272,10 @@ HTMLEditor::DoContentInserted(nsIDocument* aDocument,
return;
}
nsCOMPtr<nsIHTMLEditor> kungFuDeathGrip(this);
// XXX Why do we need this? This method is a helper of mutation observer.
// So, the callers of mutation observer should guarantee that this won't
// be deleted at least during the call.
RefPtr<HTMLEditor> kungFuDeathGrip(this);
if (ShouldReplaceRootElement()) {
nsContentUtils::AddScriptRunner(
@ -3322,7 +3325,10 @@ HTMLEditor::ContentRemoved(nsIDocument* aDocument,
return;
}
nsCOMPtr<nsIHTMLEditor> kungFuDeathGrip(this);
// XXX Why do we need to do this? This method is a mutation observer's
// method. Therefore, the caller should guarantee that this won't be
// deleted during the call.
RefPtr<HTMLEditor> kungFuDeathGrip(this);
if (SameCOMIdentity(aChild, mRootElement)) {
nsContentUtils::AddScriptRunner(
@ -3446,7 +3452,7 @@ HTMLEditor::StyleSheetLoaded(StyleSheet* aSheet,
bool aWasAlternate,
nsresult aStatus)
{
AutoEditBatch batchIt(this);
AutoPlaceholderBatch batchIt(this);
if (!mLastStyleSheetURL.IsEmpty())
RemoveStyleSheet(mLastStyleSheetURL);
@ -3580,7 +3586,7 @@ HTMLEditor::SelectEntireDocument(Selection* aSelection)
NS_IMETHODIMP
HTMLEditor::SelectAll()
{
ForceCompositionEnd();
CommitComposition();
RefPtr<Selection> selection = GetSelection();
NS_ENSURE_STATE(selection);
@ -4519,7 +4525,7 @@ nsresult
HTMLEditor::SetCSSBackgroundColor(const nsAString& aColor)
{
NS_ENSURE_TRUE(mRules, NS_ERROR_NOT_INITIALIZED);
ForceCompositionEnd();
CommitComposition();
// Protect the edit rules object from dying
nsCOMPtr<nsIEditRules> rules(mRules);
@ -4529,7 +4535,7 @@ HTMLEditor::SetCSSBackgroundColor(const nsAString& aColor)
bool isCollapsed = selection->Collapsed();
AutoEditBatch batchIt(this);
AutoPlaceholderBatch batchIt(this);
AutoRules beginRulesSniffing(this, EditAction::insertElement,
nsIEditor::eNext);
AutoSelectionRestorer selectionRestorer(selection, this);

View File

@ -46,7 +46,7 @@ class nsIDOMRange;
class nsRange;
namespace mozilla {
class AutoSelectionSetterAfterTableEdit;
class HTMLEditorEventListener;
class HTMLEditRules;
class TextEditRules;
@ -836,6 +836,30 @@ protected:
void SetElementPosition(Element& aElement, int32_t aX, int32_t aY);
/**
* Reset a selected cell or collapsed selection (the caret) after table
* editing.
*
* @param aTable A table in the document.
* @param aRow The row ...
* @param aCol ... and column defining the cell where we will try to
* place the caret.
* @param aSelected If true, we select the whole cell instead of setting
* caret.
* @param aDirection If cell at (aCol, aRow) is not found, search for
* previous cell in the same column (aPreviousColumn) or
* row (ePreviousRow) or don't search for another cell
* (aNoSearch). If no cell is found, caret is place just
* before table; and if that fails, at beginning of
* document. Thus we generally don't worry about the
* return value and can use the
* AutoSelectionSetterAfterTableEdit stack-based object to
* insure we reset the caret in a table-editing method.
*/
void SetSelectionAfterTableEdit(nsIDOMElement* aTable,
int32_t aRow, int32_t aCol,
int32_t aDirection, bool aSelected);
protected:
nsTArray<OwningNonNull<nsIContentFilter>> mContentFilters;
@ -1022,6 +1046,7 @@ protected:
ParagraphSeparator mDefaultParagraphSeparator;
public:
friend class AutoSelectionSetterAfterTableEdit;
friend class HTMLEditorEventListener;
friend class HTMLEditRules;
friend class TextEditRules;

View File

@ -102,8 +102,8 @@ HTMLEditor::LoadHTML(const nsAString& aInputString)
NS_ENSURE_TRUE(mRules, NS_ERROR_NOT_INITIALIZED);
// force IME commit; set up rules sniffing and batching
ForceCompositionEnd();
AutoEditBatch beginBatching(this);
CommitComposition();
AutoPlaceholderBatch beginBatching(this);
AutoRules beginRulesSniffing(this, EditAction::loadHTML, nsIEditor::eNext);
// Get selection
@ -197,8 +197,8 @@ HTMLEditor::DoInsertHTMLWithContext(const nsAString& aInputString,
nsCOMPtr<nsIEditRules> rules(mRules);
// force IME commit; set up rules sniffing and batching
ForceCompositionEnd();
AutoEditBatch beginBatching(this);
CommitComposition();
AutoPlaceholderBatch beginBatching(this);
AutoRules beginRulesSniffing(this, EditAction::htmlPaste, nsIEditor::eNext);
// Get selection
@ -1024,7 +1024,7 @@ HTMLEditor::BlobReader::OnResult(const nsACString& aResult)
nsresult rv = ImgFromData(type, aResult, stuffToPaste);
NS_ENSURE_SUCCESS(rv, rv);
AutoEditBatch beginBatching(mHTMLEditor);
AutoPlaceholderBatch beginBatching(mHTMLEditor);
rv = mHTMLEditor->DoInsertHTMLWithContext(stuffToPaste, EmptyString(),
EmptyString(),
NS_LITERAL_STRING(kFileMime),
@ -1120,7 +1120,7 @@ HTMLEditor::InsertObject(const nsACString& aType,
rv = ImgFromData(type, imageData, stuffToPaste);
NS_ENSURE_SUCCESS(rv, rv);
AutoEditBatch beginBatching(this);
AutoPlaceholderBatch beginBatching(this);
rv = DoInsertHTMLWithContext(stuffToPaste, EmptyString(), EmptyString(),
NS_LITERAL_STRING(kFileMime),
aSourceDoc,
@ -1174,7 +1174,7 @@ HTMLEditor::InsertFromTransferable(nsITransferable* transferable,
rv = ParseCFHTML(cfhtml, getter_Copies(cffragment), getter_Copies(cfcontext));
if (NS_SUCCEEDED(rv) && !cffragment.IsEmpty()) {
AutoEditBatch beginBatching(this);
AutoPlaceholderBatch beginBatching(this);
// If we have our private HTML flavor, we will only use the fragment
// from the CF_HTML. The rest comes from the clipboard.
if (havePrivateHTMLFlavor) {
@ -1224,7 +1224,7 @@ HTMLEditor::InsertFromTransferable(nsITransferable* transferable,
}
if (!stuffToPaste.IsEmpty()) {
AutoEditBatch beginBatching(this);
AutoPlaceholderBatch beginBatching(this);
if (bestFlavor.EqualsLiteral(kHTMLMime)) {
rv = DoInsertHTMLWithContext(stuffToPaste,
aContextStr, aInfoStr, flavor,
@ -1308,7 +1308,7 @@ HTMLEditor::InsertFromDataTransfer(DataTransfer* aDataTransfer,
nsresult rv = ParseCFHTML(cfhtml, getter_Copies(cffragment), getter_Copies(cfcontext));
if (NS_SUCCEEDED(rv) && !cffragment.IsEmpty()) {
AutoEditBatch beginBatching(this);
AutoPlaceholderBatch beginBatching(this);
if (hasPrivateHTMLFlavor) {
// If we have our private HTML flavor, we will only use the fragment
@ -1337,7 +1337,7 @@ HTMLEditor::InsertFromDataTransfer(DataTransfer* aDataTransfer,
GetStringFromDataTransfer(aDataTransfer, NS_LITERAL_STRING(kHTMLContext), aIndex, contextString);
GetStringFromDataTransfer(aDataTransfer, NS_LITERAL_STRING(kHTMLInfo), aIndex, infoString);
AutoEditBatch beginBatching(this);
AutoPlaceholderBatch beginBatching(this);
if (type.EqualsLiteral(kHTMLMime)) {
return DoInsertHTMLWithContext(text,
contextString, infoString, type,
@ -1354,7 +1354,7 @@ HTMLEditor::InsertFromDataTransfer(DataTransfer* aDataTransfer,
nsAutoString text;
GetStringFromDataTransfer(aDataTransfer, type, aIndex, text);
AutoEditBatch beginBatching(this);
AutoPlaceholderBatch beginBatching(this);
return InsertTextAt(text, aDestinationNode, aDestOffset, aDoDeleteSelection);
}
}
@ -1494,7 +1494,7 @@ HTMLEditor::PasteNoFormatting(int32_t aSelectionType)
return NS_OK;
}
ForceCompositionEnd();
CommitComposition();
// Get Clipboard Service
nsresult rv;
@ -1632,7 +1632,7 @@ NS_IMETHODIMP
HTMLEditor::PasteAsCitedQuotation(const nsAString& aCitation,
int32_t aSelectionType)
{
AutoEditBatch beginBatching(this);
AutoPlaceholderBatch beginBatching(this);
AutoRules beginRulesSniffing(this, EditAction::insertQuotation,
nsIEditor::eNext);
@ -1708,7 +1708,7 @@ HTMLEditor::PasteAsPlaintextQuotation(int32_t aSelectionType)
nsAutoString stuffToPaste;
textDataObj->GetData(stuffToPaste);
NS_ASSERTION(stuffToPaste.Length() <= (len/2), "Invalid length!");
AutoEditBatch beginBatching(this);
AutoPlaceholderBatch beginBatching(this);
rv = InsertAsPlaintextQuotation(stuffToPaste, true, 0);
}
}
@ -1835,7 +1835,7 @@ HTMLEditor::InsertAsPlaintextQuotation(const nsAString& aQuotedText,
RefPtr<Selection> selection = GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
AutoEditBatch beginBatching(this);
AutoPlaceholderBatch beginBatching(this);
AutoRules beginRulesSniffing(this, EditAction::insertQuotation,
nsIEditor::eNext);
@ -1935,7 +1935,7 @@ HTMLEditor::InsertAsCitedQuotation(const nsAString& aQuotedText,
RefPtr<Selection> selection = GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
AutoEditBatch beginBatching(this);
AutoPlaceholderBatch beginBatching(this);
AutoRules beginRulesSniffing(this, EditAction::insertQuotation,
nsIEditor::eNext);

View File

@ -18,8 +18,6 @@
#include "nsIDOMEventTarget.h"
#include "nsIDOMMouseEvent.h"
#include "nsIDOMNode.h"
#include "nsIHTMLInlineTableEditor.h"
#include "nsIHTMLObjectResizer.h"
#include "nsISupportsImpl.h"
#include "nsLiteralString.h"
#include "nsQueryObject.h"

Some files were not shown because too many files have changed in this diff Show More