зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to inbound, a=merge
MozReview-Commit-ID: IVwrN2VivZT
This commit is contained in:
Коммит
5dd57ee395
|
@ -8,60 +8,58 @@ obj*/**
|
|||
# If you are enabling a directory, please add directory specific exclusions
|
||||
# below.
|
||||
addon-sdk/**
|
||||
build/**
|
||||
chrome/**
|
||||
config/**
|
||||
db/**
|
||||
docshell/**
|
||||
editor/**
|
||||
embedding/**
|
||||
extensions/**
|
||||
extensions/cookie/**
|
||||
extensions/spellcheck/**
|
||||
extensions/universalchardet/**
|
||||
gfx/**
|
||||
gradle/**
|
||||
hal/**
|
||||
image/**
|
||||
intl/**
|
||||
ipc/**
|
||||
layout/**
|
||||
media/**
|
||||
memory/**
|
||||
mfbt/**
|
||||
modules/**
|
||||
mozglue/**
|
||||
netwerk/**
|
||||
nsprpub/**
|
||||
other-licenses/**
|
||||
parser/**
|
||||
probes/**
|
||||
python/**
|
||||
rdf/**
|
||||
servo/**
|
||||
startupcache/**
|
||||
tools/update-packaging/**
|
||||
uriloader/**
|
||||
view/**
|
||||
widget/**
|
||||
xpcom/**
|
||||
xpfe/**
|
||||
xulrunner/**
|
||||
|
||||
# b2g exclusions (pref files).
|
||||
b2g/app/b2g.js
|
||||
b2g/graphene/graphene.js
|
||||
b2g/locales/en-US/b2g-l10n.js
|
||||
# We currently have no js files in these directories, so we ignore them by
|
||||
# default to aid ESLint's performance.
|
||||
build/**
|
||||
db/**
|
||||
gradle/**
|
||||
hal/**
|
||||
mfbt/**
|
||||
mozglue/**
|
||||
nsprpub/**
|
||||
other-licenses/**
|
||||
probes/**
|
||||
startupcache/**
|
||||
xpfe/**
|
||||
|
||||
# browser/ exclusions
|
||||
browser/app/**
|
||||
browser/branding/**/firefox-branding.js
|
||||
browser/base/content/test/general/file_csp_block_all_mixedcontent.html
|
||||
# Gzipped test file.
|
||||
browser/base/content/test/general/gZipOfflineChild.html
|
||||
browser/base/content/test/urlbar/file_blank_but_not_blank.html
|
||||
# New tab is likely to be replaced soon.
|
||||
browser/base/content/newtab/**
|
||||
# Test files that are really json not js, and don't need to be linted.
|
||||
browser/components/sessionstore/test/unit/data/sessionstore_valid.js
|
||||
browser/components/sessionstore/test/unit/data/sessionstore_invalid.js
|
||||
browser/components/tabview/**
|
||||
# generated & special files in cld2
|
||||
browser/components/translation/cld2/**
|
||||
# Screenshots and Follow-on search are imported as a system add-on and have
|
||||
|
@ -73,10 +71,11 @@ browser/extensions/pdfjs/content/web**
|
|||
# generated or library files in pocket
|
||||
browser/extensions/pocket/content/panels/js/tmpl.js
|
||||
browser/extensions/pocket/content/panels/js/vendor/**
|
||||
browser/locales/**
|
||||
# generated or library files in activity-stream
|
||||
browser/extensions/activity-stream/data/content/activity-stream.bundle.js
|
||||
browser/extensions/activity-stream/vendor/**
|
||||
# The only file in browser/locales/ is pre-processed.
|
||||
browser/locales/**
|
||||
# imported from chromium
|
||||
browser/extensions/mortar/**
|
||||
|
||||
|
@ -268,7 +267,6 @@ js/src/Y.js
|
|||
mobile/android/tests/browser/chrome/tp5/**
|
||||
|
||||
# Uses `#filter substitution`
|
||||
mobile/android/b2gdroid/app/b2gdroid.js
|
||||
mobile/android/app/mobile.js
|
||||
mobile/android/chrome/content/healthreport-prefs.js
|
||||
|
||||
|
@ -283,13 +281,10 @@ mobile/android/locales/
|
|||
mobile/android/chrome/content/browser.js
|
||||
mobile/android/components/Snippets.js
|
||||
|
||||
# Bug 1178739: Ignore this file as a quick fix for "Illegal yield expression"
|
||||
mobile/android/modules/HomeProvider.jsm
|
||||
|
||||
# security/ exclusions (pref files).
|
||||
security/manager/ssl/security-prefs.js
|
||||
|
||||
#NSS
|
||||
# NSS / taskcluster only.
|
||||
security/nss/**
|
||||
|
||||
# services/ exclusions
|
||||
|
@ -342,6 +337,7 @@ toolkit/modules/tests/xpcshell/test_task.js
|
|||
|
||||
# Not yet updated
|
||||
toolkit/components/osfile/**
|
||||
toolkit/components/url-classifier/**
|
||||
|
||||
# External code:
|
||||
toolkit/components/microformats/test/**
|
||||
|
@ -352,13 +348,10 @@ toolkit/components/reader/JSDOMParser.js
|
|||
# Uses preprocessing
|
||||
toolkit/content/widgets/wizard.xml
|
||||
toolkit/components/jsdownloads/src/DownloadIntegration.jsm
|
||||
toolkit/components/url-classifier/**
|
||||
toolkit/components/urlformatter/nsURLFormatter.js
|
||||
toolkit/modules/AppConstants.jsm
|
||||
toolkit/mozapps/downloads/nsHelperAppDlg.js
|
||||
toolkit/mozapps/extensions/internal/AddonConstants.jsm
|
||||
toolkit/mozapps/update/tests/data/xpcshellConstantsPP.js
|
||||
toolkit/webapps/**
|
||||
|
||||
# Third party
|
||||
toolkit/modules/third_party/**
|
||||
|
|
|
@ -377,11 +377,11 @@ this.AccessFu = { // jshint ignore:line
|
|||
// We delay this for half a second so the awesomebar could close,
|
||||
// and we could use the current coordinates for the content item.
|
||||
// XXX TODO figure out how to avoid magic wait here.
|
||||
this.autoMove({
|
||||
delay: 500,
|
||||
forcePresent: true,
|
||||
noOpIfOnScreen: true,
|
||||
moveMethod: 'moveFirst' });
|
||||
this.autoMove({
|
||||
delay: 500,
|
||||
forcePresent: true,
|
||||
noOpIfOnScreen: true,
|
||||
moveMethod: 'moveFirst' });
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -660,7 +660,7 @@ this.Logger = { // jshint ignore:line
|
|||
let pivot = aEvent.accessible.QueryInterface(
|
||||
Ci.nsIAccessibleDocument).virtualCursor;
|
||||
str += ' (' + this.accessibleToString(event.oldAccessible) + ' -> ' +
|
||||
this.accessibleToString(pivot.position) + ')';
|
||||
this.accessibleToString(pivot.position) + ')';
|
||||
}
|
||||
|
||||
return str;
|
||||
|
|
|
@ -19,31 +19,31 @@
|
|||
|
||||
<script>
|
||||
function dumpAccessibleNode(aNode, level) {
|
||||
var msg = "";
|
||||
var msg = "";
|
||||
|
||||
try {
|
||||
msg += "name=\"" + aNode.name + "\" ";
|
||||
} catch (e) {
|
||||
msg += " noName ";
|
||||
}
|
||||
try {
|
||||
msg += "name=\"" + aNode.name + "\" ";
|
||||
} catch (e) {
|
||||
msg += " noName ";
|
||||
}
|
||||
|
||||
dump(msg + '\n');
|
||||
dump(msg + '\n');
|
||||
}
|
||||
|
||||
|
||||
function dumpAccessibleTree(aNode, level) {
|
||||
level = level || 0;
|
||||
level = level || 0;
|
||||
|
||||
dumpAccessibleNode(aNode, level);
|
||||
try {
|
||||
var child = aNode.firstChild;
|
||||
while (child) {
|
||||
dumpAccessibleTree(child, level + 1);
|
||||
child = child.nextSibling;
|
||||
}
|
||||
} catch (e) {
|
||||
dump("Error visiting child nodes: " + e + '\n');
|
||||
}
|
||||
dumpAccessibleNode(aNode, level);
|
||||
try {
|
||||
var child = aNode.firstChild;
|
||||
while (child) {
|
||||
dumpAccessibleTree(child, level + 1);
|
||||
child = child.nextSibling;
|
||||
}
|
||||
} catch (e) {
|
||||
dump("Error visiting child nodes: " + e + '\n');
|
||||
}
|
||||
}
|
||||
|
||||
function A(o) {
|
||||
|
|
|
@ -20,7 +20,7 @@ Cu.import("resource://gre/modules/accessibility/OutputGenerator.jsm", this);
|
|||
function testContextOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID, aGenerator) {
|
||||
var accessible = getAccessible(aAccOrElmOrID);
|
||||
var oldAccessible = aOldAccOrElmOrID !== null ?
|
||||
getAccessible(aOldAccOrElmOrID || 'root') : null;
|
||||
getAccessible(aOldAccOrElmOrID || 'root') : null;
|
||||
var context = new PivotContext(accessible, oldAccessible);
|
||||
var output = aGenerator.genForContext(context);
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
{ SECTION: [
|
||||
{ SECTION: [
|
||||
{ TEXT_LEAF: [ ] }
|
||||
] }
|
||||
] }
|
||||
] };
|
||||
testAccessibleTree("table2", accTree);
|
||||
|
||||
|
|
|
@ -148,7 +148,7 @@
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// area6 (CSS vertical-align property, refer to bug 445938 for details
|
||||
// and sup and sub elements, refer to bug 735645 for details)
|
||||
// and sup and sub elements, refer to bug 735645 for details)
|
||||
ID = "area6";
|
||||
defAttrs = buildDefaultTextAttrs(ID, "12pt");
|
||||
testDefaultTextAttrs(ID, defAttrs);
|
||||
|
|
|
@ -5785,8 +5785,8 @@ function contentAreaClick(event, isPanelClick) {
|
|||
title: linkNode.getAttribute("title"),
|
||||
loadBookmarkInSidebar: true,
|
||||
hiddenRows: [ "description",
|
||||
"location",
|
||||
"keyword" ]
|
||||
"location",
|
||||
"keyword" ]
|
||||
}, window);
|
||||
event.preventDefault();
|
||||
return;
|
||||
|
|
|
@ -300,7 +300,7 @@ function test_emitLatchedEvents(eventPrefix, initialDelta, cmd) {
|
|||
|
||||
// Now go back in the opposite direction.
|
||||
test_utils.sendSimpleGestureEvent(eventPrefix + "Update", 0, 0, 0,
|
||||
-initialDelta, 0);
|
||||
-initialDelta, 0);
|
||||
cumulativeDelta += -initialDelta;
|
||||
if (isIncreasing) {
|
||||
expect.dec++;
|
||||
|
@ -321,7 +321,7 @@ function test_emitLatchedEvents(eventPrefix, initialDelta, cmd) {
|
|||
|
||||
// Go back to the original direction. The original command should trigger.
|
||||
test_utils.sendSimpleGestureEvent(eventPrefix + "Update", 0, 0, 0,
|
||||
initialDelta, 0);
|
||||
initialDelta, 0);
|
||||
cumulativeDelta += initialDelta;
|
||||
if (isIncreasing) {
|
||||
expect.inc++;
|
||||
|
|
|
@ -1183,9 +1183,9 @@ const CustomizableWidgets = [
|
|||
observe(aSubject, aTopic, aData) {
|
||||
let {instances} = CustomizableUI.getWidget("containers-panelmenu");
|
||||
for (let {node} of instances) {
|
||||
if (node) {
|
||||
this.updateVisibility(node);
|
||||
}
|
||||
if (node) {
|
||||
this.updateVisibility(node);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -534,8 +534,9 @@ const PanelUI = {
|
|||
CustomizableUI.removePanelCloseListeners(tempPanel);
|
||||
tempPanel.removeEventListener("popuphidden", panelRemover);
|
||||
|
||||
let evt = new CustomEvent("ViewHiding", {detail: viewNode});
|
||||
viewNode.dispatchEvent(evt);
|
||||
let currentView = multiView.current || viewNode;
|
||||
let evt = new CustomEvent("ViewHiding", {detail: currentView});
|
||||
currentView.dispatchEvent(evt);
|
||||
}
|
||||
aAnchor.open = false;
|
||||
|
||||
|
|
|
@ -89,8 +89,8 @@ ESE.JET_COLTYP = ctypes.unsigned_long;
|
|||
ESE.JET_DBID = ctypes.unsigned_long;
|
||||
|
||||
ESE.JET_COLUMNDEF = new ctypes.StructType("JET_COLUMNDEF", [
|
||||
{"cbStruct": ctypes.unsigned_long},
|
||||
{"columnid": ESE.JET_COLUMNID },
|
||||
{"cbStruct": ctypes.unsigned_long },
|
||||
{"columnid": ESE.JET_COLUMNID },
|
||||
{"coltyp": ESE.JET_COLTYP },
|
||||
{"wCountry": ctypes.unsigned_short }, // sepcifies the country/region for the column definition
|
||||
{"langid": ctypes.unsigned_short },
|
||||
|
|
|
@ -371,9 +371,9 @@ var BookmarkPropertiesPanel = {
|
|||
}
|
||||
},
|
||||
|
||||
// Hack for implementing batched-Undo around the editBookmarkOverlay
|
||||
// instant-apply code. For all the details see the comment above beginBatch
|
||||
// in browser-places.js
|
||||
// Hack for implementing batched-Undo around the editBookmarkOverlay
|
||||
// instant-apply code. For all the details see the comment above beginBatch
|
||||
// in browser-places.js
|
||||
_batchBlockingDeferred: null,
|
||||
_beginBatch() {
|
||||
if (this._batching)
|
||||
|
|
|
@ -278,7 +278,7 @@ const CONFIRM_RESTART_PROMPT_CANCEL = 1;
|
|||
const CONFIRM_RESTART_PROMPT_RESTART_LATER = 2;
|
||||
function confirmRestartPrompt(aRestartToEnable, aDefaultButtonIndex,
|
||||
aWantRevertAsCancelButton,
|
||||
aWantRestartLaterButton) {
|
||||
aWantRestartLaterButton) {
|
||||
let brandName = document.getElementById("bundleBrand").getString("brandShortName");
|
||||
let bundle = document.getElementById("bundlePreferences");
|
||||
let msg = bundle.getFormattedString(aRestartToEnable ?
|
||||
|
|
|
@ -39,6 +39,7 @@ skip-if = true || !healthreport # Bug 1185403 for the "true"
|
|||
[browser_layersacceleration.js]
|
||||
[browser_masterpassword.js]
|
||||
[browser_notifications_do_not_disturb.js]
|
||||
[browser_password_management.js]
|
||||
[browser_performance.js]
|
||||
skip-if = !e10s
|
||||
[browser_performance_non_e10s.js]
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
"use strict";
|
||||
const PM_URL = "chrome://passwordmgr/content/passwordManager.xul";
|
||||
|
||||
var passwordsDialog;
|
||||
|
||||
add_task(async function test_setup() {
|
||||
let pwmgr = Cc["@mozilla.org/login-manager;1"].
|
||||
getService(Ci.nsILoginManager);
|
||||
pwmgr.removeAllLogins();
|
||||
|
||||
// add login data
|
||||
let nsLoginInfo = new Components.Constructor("@mozilla.org/login-manager/loginInfo;1",
|
||||
Ci.nsILoginInfo, "init");
|
||||
let login = new nsLoginInfo("http://example.com/", "http://example.com/", null,
|
||||
"user", "password", "u1", "p1");
|
||||
pwmgr.addLogin(login);
|
||||
|
||||
registerCleanupFunction(async function() {
|
||||
pwmgr.removeAllLogins();
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_openPasswordSubDialog() {
|
||||
// Undo the save password change.
|
||||
registerCleanupFunction(async function() {
|
||||
await ContentTask.spawn(gBrowser.selectedBrowser, null, function() {
|
||||
let doc = content.document;
|
||||
let savePasswordCheckBox = doc.getElementById("savePasswords");
|
||||
if (savePasswordCheckBox.checked) {
|
||||
savePasswordCheckBox.click();
|
||||
}
|
||||
});
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
await openPreferencesViaOpenPreferencesAPI("privacy", {leaveOpen: true});
|
||||
|
||||
let dialogOpened = promiseLoadSubDialog(PM_URL);
|
||||
|
||||
await ContentTask.spawn(gBrowser.selectedBrowser, null, function() {
|
||||
let doc = content.document;
|
||||
let savePasswordCheckBox = doc.getElementById("savePasswords");
|
||||
Assert.ok(!savePasswordCheckBox.checked,
|
||||
"Save Password CheckBox should be unchecked by default");
|
||||
savePasswordCheckBox.click();
|
||||
|
||||
let showPasswordsButton = doc.getElementById("showPasswords");
|
||||
showPasswordsButton.click();
|
||||
});
|
||||
|
||||
passwordsDialog = await dialogOpened;
|
||||
});
|
||||
|
||||
add_task(async function test_deletePasswordWithKey() {
|
||||
let doc = passwordsDialog.document;
|
||||
|
||||
let tree = doc.getElementById("signonsTree");
|
||||
Assert.equal(tree.view.rowCount, 1, "Row count should initially be 1");
|
||||
tree.focus();
|
||||
tree.view.selection.select(0);
|
||||
|
||||
if (AppConstants.platform == "macosx") {
|
||||
EventUtils.synthesizeKey("VK_BACK_SPACE", {});
|
||||
} else {
|
||||
EventUtils.synthesizeKey("VK_DELETE", {});
|
||||
}
|
||||
|
||||
await waitForCondition(() => tree.view.rowCount == 0);
|
||||
|
||||
is_element_visible(content.gSubDialog._dialogs[0]._box,
|
||||
"Subdialog is visible after deleting an element");
|
||||
});
|
|
@ -245,7 +245,7 @@ const CONFIRM_RESTART_PROMPT_CANCEL = 1;
|
|||
const CONFIRM_RESTART_PROMPT_RESTART_LATER = 2;
|
||||
function confirmRestartPrompt(aRestartToEnable, aDefaultButtonIndex,
|
||||
aWantRevertAsCancelButton,
|
||||
aWantRestartLaterButton) {
|
||||
aWantRestartLaterButton) {
|
||||
let brandName = document.getElementById("bundleBrand").getString("brandShortName");
|
||||
let bundle = document.getElementById("bundlePreferences");
|
||||
let msg = bundle.getFormattedString(aRestartToEnable ?
|
||||
|
|
|
@ -29,6 +29,7 @@ skip-if = os != "win" # This test tests the windows-specific app selection dialo
|
|||
skip-if = true || !healthreport # Bug 1185403 for the "true"
|
||||
[browser_homepages_filter_aboutpreferences.js]
|
||||
[browser_notifications_do_not_disturb.js]
|
||||
[browser_password_management.js]
|
||||
[browser_performance.js]
|
||||
skip-if = !e10s
|
||||
[browser_performance_non_e10s.js]
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
"use strict";
|
||||
const PM_URL = "chrome://passwordmgr/content/passwordManager.xul";
|
||||
|
||||
var passwordsDialog;
|
||||
|
||||
add_task(async function setup() {
|
||||
Services.logins.removeAllLogins();
|
||||
|
||||
// add login data
|
||||
let nsLoginInfo = new Components.Constructor("@mozilla.org/login-manager/loginInfo;1",
|
||||
Ci.nsILoginInfo, "init");
|
||||
let login = new nsLoginInfo("http://example.com/", "http://example.com/", null,
|
||||
"user", "password", "u1", "p1");
|
||||
Services.logins.addLogin(login);
|
||||
|
||||
registerCleanupFunction(async function() {
|
||||
Services.logins.removeAllLogins();
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_openPasswordSubDialog() {
|
||||
// Undo the save password change.
|
||||
registerCleanupFunction(async function() {
|
||||
await ContentTask.spawn(gBrowser.selectedBrowser, null, function() {
|
||||
let doc = content.document;
|
||||
let savePasswordCheckBox = doc.getElementById("savePasswords");
|
||||
if (savePasswordCheckBox.checked) {
|
||||
savePasswordCheckBox.click();
|
||||
}
|
||||
});
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
await openPreferencesViaOpenPreferencesAPI("security", null, {leaveOpen: true});
|
||||
|
||||
let dialogOpened = promiseLoadSubDialog(PM_URL);
|
||||
|
||||
await ContentTask.spawn(gBrowser.selectedBrowser, null, function() {
|
||||
let doc = content.document;
|
||||
let savePasswordCheckBox = doc.getElementById("savePasswords");
|
||||
Assert.ok(!savePasswordCheckBox.checked,
|
||||
"Save Password CheckBox should be unchecked by default");
|
||||
savePasswordCheckBox.click();
|
||||
|
||||
let showPasswordsButton = doc.getElementById("showPasswords");
|
||||
showPasswordsButton.click();
|
||||
});
|
||||
|
||||
passwordsDialog = await dialogOpened;
|
||||
});
|
||||
|
||||
add_task(async function test_deletePasswordWithKey() {
|
||||
let doc = passwordsDialog.document;
|
||||
|
||||
let tree = doc.getElementById("signonsTree");
|
||||
Assert.equal(tree.view.rowCount, 1, "Row count should initially be 1");
|
||||
tree.focus();
|
||||
tree.view.selection.select(0);
|
||||
|
||||
if (AppConstants.platform == "macosx") {
|
||||
EventUtils.synthesizeKey("VK_BACK_SPACE", {});
|
||||
} else {
|
||||
EventUtils.synthesizeKey("VK_DELETE", {});
|
||||
}
|
||||
|
||||
await waitForCondition(() => tree.view.rowCount == 0);
|
||||
|
||||
is_element_visible(content.gSubDialog._dialogs[0]._box,
|
||||
"Subdialog is visible after deleting an element");
|
||||
});
|
|
@ -3,24 +3,16 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {classes: Cc, interfaces: Ci} = Components;
|
||||
|
||||
/**
|
||||
* Make sure that tabs are restored on demand as otherwise the tab will start
|
||||
* loading immediately and we can't check its icon and label.
|
||||
*/
|
||||
add_task(function setup() {
|
||||
Services.prefs.setBoolPref("browser.sessionstore.restore_on_demand", true);
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("browser.sessionstore.restore_on_demand");
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Ensure that a pending tab has label and icon correctly set.
|
||||
*/
|
||||
add_task(async function test_label_and_icon() {
|
||||
// Make sure that tabs are restored on demand as otherwise the tab will start
|
||||
// loading immediately and we can't check its icon and label.
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.sessionstore.restore_on_demand", true]],
|
||||
});
|
||||
|
||||
// Create a new tab.
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, "about:robots");
|
||||
let browser = tab.linkedBrowser;
|
||||
|
|
|
@ -20,19 +20,17 @@ add_task(async function() {
|
|||
const ABOUT_ROBOTS_URI = "about:robots";
|
||||
const ABOUT_ROBOTS_TITLE = "Gort! Klaatu barada nikto!";
|
||||
|
||||
function observeLabelChanges(tab) {
|
||||
info("observing tab label changes. initial label: " + tab.label);
|
||||
let labelChangeCount = 0;
|
||||
function observeLabelChanges(tab, expectedLabels) {
|
||||
let seenLabels = [tab.label];
|
||||
function TabAttrModifiedListener(event) {
|
||||
if (event.detail.changed.some(attr => { return attr == "label" })) {
|
||||
info("tab label change: " + tab.label);
|
||||
labelChangeCount++;
|
||||
if (event.detail.changed.some(attr => attr == "label")) {
|
||||
seenLabels.push(tab.label);
|
||||
}
|
||||
}
|
||||
tab.addEventListener("TabAttrModified", TabAttrModifiedListener);
|
||||
return (expectedCount) => {
|
||||
return () => {
|
||||
tab.removeEventListener("TabAttrModified", TabAttrModifiedListener);
|
||||
is(labelChangeCount, expectedCount, "observed tab label changes");
|
||||
is(JSON.stringify(seenLabels), JSON.stringify(expectedLabels || []), "observed tab label changes");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,33 +57,29 @@ add_task(async function() {
|
|||
is(firstTab.label, CONTENT_TITLE, "first tab displays content title");
|
||||
ok(document.title.startsWith(CONTENT_TITLE), "title bar displays content title");
|
||||
ok(secondTab.hasAttribute("pending"), "second tab is pending");
|
||||
ok(thirdTab.hasAttribute("pending"), "third tab is pending");
|
||||
|
||||
info("selecting the second tab");
|
||||
// The fix for bug 1364127 caused about: pages' initial tab titles to show
|
||||
// their about: URIs until their actual page titles are known, e.g.
|
||||
// "about:addons" -> "Add-ons Manager". This is bug 1371896. Previously,
|
||||
// about: pages' initial tab titles were blank until the page title was known.
|
||||
is(secondTab.label, ABOUT_ROBOTS_URI, "second tab displays URI as its initial title");
|
||||
ok(thirdTab.hasAttribute("pending"), "third tab is pending");
|
||||
is(thirdTab.label, "example.com", "third tab displays hostname without www as its initial title");
|
||||
|
||||
info("selecting the second tab");
|
||||
let checkLabelChangeCount = observeLabelChanges(secondTab);
|
||||
let finishObservingLabelChanges = observeLabelChanges(secondTab, [ABOUT_ROBOTS_URI, ABOUT_ROBOTS_TITLE]);
|
||||
browserLoadedPromise = BrowserTestUtils.browserLoaded(secondTab.linkedBrowser, false, ABOUT_ROBOTS_URI);
|
||||
gBrowser.selectedTab = secondTab;
|
||||
await browserLoadedPromise;
|
||||
ok(!secondTab.hasAttribute("pending"), "second tab isn't pending anymore");
|
||||
is(secondTab.label, ABOUT_ROBOTS_TITLE, "second tab displays content title");
|
||||
ok(document.title.startsWith(ABOUT_ROBOTS_TITLE), "title bar displays content title");
|
||||
checkLabelChangeCount(1); // ABOUT_ROBOTS_URI -> ABOUT_ROBOTS_TITLE
|
||||
finishObservingLabelChanges();
|
||||
|
||||
info("selecting the third tab");
|
||||
checkLabelChangeCount = observeLabelChanges(thirdTab);
|
||||
finishObservingLabelChanges = observeLabelChanges(thirdTab, ["example.com", CONTENT_TITLE]);
|
||||
browserLoadedPromise = BrowserTestUtils.browserLoaded(thirdTab.linkedBrowser, false, TEST_URL);
|
||||
gBrowser.selectedTab = thirdTab;
|
||||
await browserLoadedPromise;
|
||||
ok(!thirdTab.hasAttribute("pending"), "third tab isn't pending anymore");
|
||||
is(thirdTab.label, CONTENT_TITLE, "third tab displays content title");
|
||||
ok(document.title.startsWith(CONTENT_TITLE), "title bar displays content title");
|
||||
checkLabelChangeCount(1); // TEST_URL -> CONTENT_TITLE
|
||||
finishObservingLabelChanges();
|
||||
|
||||
info("restoring the modified browser state");
|
||||
await TabStateFlusher.flushWindow(window);
|
||||
|
@ -94,21 +88,19 @@ add_task(async function() {
|
|||
is(thirdTab, gBrowser.selectedTab, "third tab is selected after restoring");
|
||||
ok(document.title.startsWith(CONTENT_TITLE), "title bar displays content title");
|
||||
ok(firstTab.hasAttribute("pending"), "first tab is pending after restoring");
|
||||
is(firstTab.label, CONTENT_TITLE, "first tab displays content title in pending state");
|
||||
ok(secondTab.hasAttribute("pending"), "second tab is pending after restoring");
|
||||
is(secondTab.label, ABOUT_ROBOTS_TITLE, "second tab displays content title");
|
||||
ok(!thirdTab.hasAttribute("pending"), "third tab is not pending after restoring");
|
||||
is(thirdTab.label, CONTENT_TITLE, "third tab displays content title in pending state");
|
||||
|
||||
info("selecting the first tab");
|
||||
checkLabelChangeCount = observeLabelChanges(firstTab);
|
||||
finishObservingLabelChanges = observeLabelChanges(firstTab, [CONTENT_TITLE]);
|
||||
let tabContentRestored = TestUtils.topicObserved("sessionstore-debug-tab-restored");
|
||||
gBrowser.selectedTab = firstTab;
|
||||
ok(document.title.startsWith(CONTENT_TITLE), "title bar displays content title");
|
||||
await tabContentRestored;
|
||||
ok(!firstTab.hasAttribute("pending"), "first tab isn't pending anymore");
|
||||
checkLabelChangeCount(0);
|
||||
is(firstTab.label, CONTENT_TITLE, "first tab displays content title after restoring content");
|
||||
finishObservingLabelChanges();
|
||||
|
||||
await promiseBrowserState(BACKUP_STATE);
|
||||
});
|
||||
|
|
|
@ -59,9 +59,9 @@ if (typeof Mozilla == "undefined") {
|
|||
|
||||
function listener(event) {
|
||||
if (typeof event.detail != "object")
|
||||
return;
|
||||
return;
|
||||
if (event.detail.callbackID != id)
|
||||
return;
|
||||
return;
|
||||
|
||||
document.removeEventListener("mozUITourResponse", listener);
|
||||
callback(event.detail.data);
|
||||
|
@ -266,12 +266,12 @@ if (typeof Mozilla == "undefined") {
|
|||
var buttonData = [];
|
||||
if (Array.isArray(buttons)) {
|
||||
for (var i = 0; i < buttons.length; i++) {
|
||||
buttonData.push({
|
||||
label: buttons[i].label,
|
||||
icon: buttons[i].icon,
|
||||
style: buttons[i].style,
|
||||
callbackID: _waitForCallback(buttons[i].callback)
|
||||
});
|
||||
buttonData.push({
|
||||
label: buttons[i].label,
|
||||
icon: buttons[i].icon,
|
||||
style: buttons[i].style,
|
||||
callbackID: _waitForCallback(buttons[i].callback)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -371,8 +371,8 @@ if (typeof Mozilla == "undefined") {
|
|||
themes.push(theme);
|
||||
|
||||
_sendEvent("previewTheme", {
|
||||
theme: JSON.stringify(theme),
|
||||
state: true
|
||||
theme: JSON.stringify(theme),
|
||||
state: true
|
||||
});
|
||||
|
||||
callback(theme);
|
||||
|
|
|
@ -23,18 +23,18 @@ var pktPanelMessaging = (function() {
|
|||
function addMessageListener(panelId, messageId, callback) {
|
||||
document.addEventListener(panelPrefixedMessageId(panelId, messageId), function(e) {
|
||||
|
||||
callback(JSON.parse(e.target.getAttribute("payload"))[0]);
|
||||
callback(JSON.parse(e.target.getAttribute("payload"))[0]);
|
||||
|
||||
// TODO: Figure out why e.target.parentNode is null
|
||||
// e.target.parentNode.removeChild(e.target);
|
||||
// TODO: Figure out why e.target.parentNode is null
|
||||
// e.target.parentNode.removeChild(e.target);
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function removeMessageListener(panelId, messageId, callback) {
|
||||
function removeMessageListener(panelId, messageId, callback) {
|
||||
document.removeEventListener(panelPrefixedMessageId(panelId, messageId), callback);
|
||||
}
|
||||
}
|
||||
|
||||
function sendMessage(panelId, messageId, payload, callback) {
|
||||
// Payload needs to be an object in format:
|
||||
|
@ -44,26 +44,26 @@ var pktPanelMessaging = (function() {
|
|||
data: (payload || {})
|
||||
};
|
||||
|
||||
// Create a callback to listen for a response
|
||||
if (callback) {
|
||||
var messageResponseId = messageId + "Response";
|
||||
var responseListener = function(responsePayload) {
|
||||
callback(responsePayload);
|
||||
removeMessageListener(panelId, messageResponseId, responseListener);
|
||||
}
|
||||
// Create a callback to listen for a response
|
||||
if (callback) {
|
||||
var messageResponseId = messageId + "Response";
|
||||
var responseListener = function(responsePayload) {
|
||||
callback(responsePayload);
|
||||
removeMessageListener(panelId, messageResponseId, responseListener);
|
||||
}
|
||||
|
||||
addMessageListener(panelId, messageResponseId, responseListener);
|
||||
}
|
||||
addMessageListener(panelId, messageResponseId, responseListener);
|
||||
}
|
||||
|
||||
// Send message
|
||||
var element = document.createElement("PKTMessageFromPanelElement");
|
||||
element.setAttribute("payload", JSON.stringify([messagePayload]));
|
||||
document.documentElement.appendChild(element);
|
||||
// Send message
|
||||
var element = document.createElement("PKTMessageFromPanelElement");
|
||||
element.setAttribute("payload", JSON.stringify([messagePayload]));
|
||||
document.documentElement.appendChild(element);
|
||||
|
||||
var evt = document.createEvent("Events");
|
||||
evt.initEvent(prefixedMessageId(messageId), true, false);
|
||||
element.dispatchEvent(evt);
|
||||
}
|
||||
var evt = document.createEvent("Events");
|
||||
evt.initEvent(prefixedMessageId(messageId), true, false);
|
||||
element.dispatchEvent(evt);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -34,20 +34,20 @@ this.ContentWebRTC = {
|
|||
observe(aSubject, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
case "getUserMedia:request":
|
||||
handleGUMRequest(aSubject, aTopic, aData);
|
||||
break;
|
||||
handleGUMRequest(aSubject, aTopic, aData);
|
||||
break;
|
||||
case "recording-device-stopped":
|
||||
handleGUMStop(aSubject, aTopic, aData);
|
||||
break;
|
||||
handleGUMStop(aSubject, aTopic, aData);
|
||||
break;
|
||||
case "PeerConnection:request":
|
||||
handlePCRequest(aSubject, aTopic, aData);
|
||||
break;
|
||||
handlePCRequest(aSubject, aTopic, aData);
|
||||
break;
|
||||
case "recording-device-events":
|
||||
updateIndicators(aSubject, aTopic, aData);
|
||||
break;
|
||||
updateIndicators(aSubject, aTopic, aData);
|
||||
break;
|
||||
case "recording-window-ended":
|
||||
removeBrowserSpecificIndicator(aSubject, aTopic, aData);
|
||||
break;
|
||||
removeBrowserSpecificIndicator(aSubject, aTopic, aData);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -263,9 +263,11 @@
|
|||
background-image: url("chrome://browser/content/default-theme-icon.svg");
|
||||
}
|
||||
|
||||
%ifdef MOZ_PHOTON_THEME
|
||||
#customization-uidensity-button > .box-inherit > .box-inherit > .button-icon {
|
||||
background-image: url("chrome://browser/skin/customizableui/density-normal.svg");
|
||||
}
|
||||
%endif
|
||||
|
||||
%ifndef MOZ_PHOTON_THEME
|
||||
#main-window[customize-entered] #customization-panel-container {
|
||||
|
@ -462,6 +464,7 @@ toolbarpaletteitem[place="toolbar"]:not([mousedown="true"]):-moz-focusring {
|
|||
list-style-image: url(chrome://browser/content/default-theme-icon.svg);
|
||||
}
|
||||
|
||||
%ifdef MOZ_PHOTON_THEME
|
||||
#customization-uidensity-menu-button-normal {
|
||||
list-style-image: url("chrome://browser/skin/customizableui/density-normal.svg");
|
||||
}
|
||||
|
@ -473,6 +476,7 @@ toolbarpaletteitem[place="toolbar"]:not([mousedown="true"]):-moz-focusring {
|
|||
#customization-uidensity-menu-button-touch {
|
||||
list-style-image: url("chrome://browser/skin/customizableui/density-touch.svg");
|
||||
}
|
||||
%endif
|
||||
|
||||
.customization-uidensity-menu-button[active="true"],
|
||||
.customization-uidensity-menu-button:hover,
|
||||
|
|
|
@ -664,8 +664,12 @@ menulist[indicator=true] > menupopup menuitem:not([image]) > .menu-iconic-left {
|
|||
}
|
||||
|
||||
menulist[indicator=true] > menupopup menuitem[indicator=true]:not([image]) > .menu-iconic-left > .menu-iconic-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/search-arrow-indicator.svg);
|
||||
list-style-image: url(chrome://browser/skin/preferences/in-content-new/search-arrow-indicator.svg);
|
||||
width: 8px;
|
||||
height: 10px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
menulist[indicator=true] > menupopup menuitem[indicator=true]:not([image]) > .menu-iconic-left > .menu-iconic-icon:-moz-locale-dir(rtl) {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
|
До Ширина: | Высота: | Размер: 581 B После Ширина: | Высота: | Размер: 581 B |
|
@ -94,6 +94,7 @@
|
|||
skin/classic/browser/panel-icon-retry.svg (../shared/panel-icon-retry.svg)
|
||||
skin/classic/browser/preferences/in-content-new/favicon.ico (../shared/incontentprefs/favicon.ico)
|
||||
skin/classic/browser/preferences/in-content-new/icons.svg (../shared/incontentprefs/icons.svg)
|
||||
skin/classic/browser/preferences/in-content-new/search-arrow-indicator.svg (../shared/incontentprefs/search-arrow-indicator.svg)
|
||||
skin/classic/browser/preferences/in-content-new/search.css (../shared/incontentprefs/search.css)
|
||||
skin/classic/browser/preferences/in-content-new/siteDataSettings.css (../shared/incontentprefs/siteDataSettings.css)
|
||||
* skin/classic/browser/preferences/in-content-new/containers.css (../shared/incontentprefs/containers.css)
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
--toolbarbutton-icon-fill-attention: #177ee5;
|
||||
}
|
||||
|
||||
:-moz-any(@primaryToolbarButtons@) {
|
||||
.toolbarbutton-1 {
|
||||
-moz-context-properties: fill;
|
||||
fill: var(--toolbarbutton-icon-fill);
|
||||
}
|
||||
|
||||
toolbar[brighttext] :-moz-any(@primaryToolbarButtons@) {
|
||||
toolbar[brighttext] .toolbarbutton-1 {
|
||||
fill: var(--toolbarbutton-icon-fill-inverted);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,9 @@ support-files =
|
|||
doc_sourcemaps.css.map
|
||||
doc_sourcemaps.html
|
||||
doc_sourcemaps.scss
|
||||
doc_sourcemaps2.css
|
||||
doc_sourcemaps2.css^headers^
|
||||
doc_sourcemaps2.html
|
||||
doc_style_editor_link.css
|
||||
doc_test_image.png
|
||||
doc_urls_clickable.css
|
||||
|
@ -192,6 +195,7 @@ skip-if = (os == "win" && debug) # bug 963492: win.
|
|||
[browser_rules_multiple_properties_01.js]
|
||||
[browser_rules_multiple_properties_02.js]
|
||||
[browser_rules_original-source-link.js]
|
||||
[browser_rules_original-source-link2.js]
|
||||
[browser_rules_pseudo-element_01.js]
|
||||
[browser_rules_pseudo-element_02.js]
|
||||
[browser_rules_pseudo_lock_options.js]
|
||||
|
|
|
@ -10,10 +10,10 @@
|
|||
const TEST_URI = `
|
||||
<style>
|
||||
div {
|
||||
background: #fff;
|
||||
font-family: sans-serif;
|
||||
url(display-table.min.htc);
|
||||
}
|
||||
background: #fff;
|
||||
font-family: sans-serif;
|
||||
url(display-table.min.htc);
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<div id="testid" class="testclass">Styled Node</div>
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that the stylesheet links in the rule view are correct when source maps
|
||||
// are involved.
|
||||
|
||||
const TESTCASE_URI = URL_ROOT + "doc_sourcemaps2.html";
|
||||
const PREF = "devtools.styleeditor.source-maps-enabled";
|
||||
const SCSS_LOC = "doc_sourcemaps.scss:4";
|
||||
const CSS_LOC = "doc_sourcemaps2.css:1";
|
||||
|
||||
add_task(function* () {
|
||||
info("Setting the " + PREF + " pref to true");
|
||||
Services.prefs.setBoolPref(PREF, true);
|
||||
|
||||
yield addTab(TESTCASE_URI);
|
||||
let {toolbox, inspector, view} = yield openRuleView();
|
||||
|
||||
info("Selecting the test node");
|
||||
yield selectNode("div", inspector);
|
||||
|
||||
yield verifyLinkText(SCSS_LOC, view);
|
||||
|
||||
info("Setting the " + PREF + " pref to false");
|
||||
Services.prefs.setBoolPref(PREF, false);
|
||||
yield verifyLinkText(CSS_LOC, view);
|
||||
|
||||
info("Setting the " + PREF + " pref to true again");
|
||||
Services.prefs.setBoolPref(PREF, true);
|
||||
|
||||
yield testClickingLink(toolbox, view);
|
||||
yield checkDisplayedStylesheet(toolbox);
|
||||
|
||||
info("Clearing the " + PREF + " pref");
|
||||
Services.prefs.clearUserPref(PREF);
|
||||
});
|
||||
|
||||
function* testClickingLink(toolbox, view) {
|
||||
info("Listening for switch to the style editor");
|
||||
let onStyleEditorReady = toolbox.once("styleeditor-ready");
|
||||
|
||||
info("Finding the stylesheet link and clicking it");
|
||||
let link = getRuleViewLinkByIndex(view, 1);
|
||||
link.scrollIntoView();
|
||||
link.click();
|
||||
yield onStyleEditorReady;
|
||||
}
|
||||
|
||||
function checkDisplayedStylesheet(toolbox) {
|
||||
let def = defer();
|
||||
|
||||
let panel = toolbox.getCurrentPanel();
|
||||
panel.UI.on("editor-selected", (event, editor) => {
|
||||
// The style editor selects the first sheet at first load before
|
||||
// selecting the desired sheet.
|
||||
if (editor.styleSheet.href.endsWith("scss")) {
|
||||
info("Original source editor selected");
|
||||
editor.getSourceEditor().then(editorSelected)
|
||||
.then(def.resolve, def.reject);
|
||||
}
|
||||
});
|
||||
|
||||
return def.promise;
|
||||
}
|
||||
|
||||
function editorSelected(editor) {
|
||||
let href = editor.styleSheet.href;
|
||||
ok(href.endsWith("doc_sourcemaps.scss"),
|
||||
"selected stylesheet is correct one");
|
||||
|
||||
let {line} = editor.sourceEditor.getCursor();
|
||||
is(line, 3, "cursor is at correct line number in original source");
|
||||
}
|
||||
|
||||
function verifyLinkText(text, view) {
|
||||
info("Verifying that the rule-view stylesheet link is " + text);
|
||||
let label = getRuleViewLinkByIndex(view, 1)
|
||||
.querySelector(".ruleview-rule-source-label");
|
||||
return waitForSuccess(function* () {
|
||||
return label.textContent == text;
|
||||
}, "Link text changed to display correct location: " + text);
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
div {
|
||||
color: #ff0066; }
|
||||
|
||||
span {
|
||||
background-color: #EEE; }
|
|
@ -0,0 +1 @@
|
|||
X-SourceMap: doc_sourcemaps.css.map
|
|
@ -0,0 +1,11 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>testcase for testing CSS source maps</title>
|
||||
<link rel="stylesheet" type="text/css" href="simple.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="doc_sourcemaps2.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div>source maps <span>testcase</span></div>
|
||||
</body>
|
||||
</html>
|
|
@ -622,6 +622,10 @@ var StyleSheetActor = protocol.ActorClassWithSpec(styleSheetSpec, {
|
|||
* Url of source map.
|
||||
*/
|
||||
_extractSourceMapUrl: function (content) {
|
||||
// If a SourceMap response header was saved on the style sheet, use it.
|
||||
if (this.rawSheet.sourceMapURL) {
|
||||
return this.rawSheet.sourceMapURL;
|
||||
}
|
||||
let matches = /sourceMappingURL\=([^\s\*]*)/.exec(content);
|
||||
if (matches) {
|
||||
return matches[1];
|
||||
|
|
|
@ -10610,6 +10610,16 @@ nsContentUtils::GetUserIsInteracting()
|
|||
return UserInteractionObserver::sUserActive;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsContentUtils::GetSourceMapURL(nsIHttpChannel* aChannel, nsACString& aResult)
|
||||
{
|
||||
nsresult rv = aChannel->GetResponseHeader(NS_LITERAL_CSTRING("SourceMap"), aResult);
|
||||
if (NS_FAILED(rv)) {
|
||||
rv = aChannel->GetResponseHeader(NS_LITERAL_CSTRING("X-SourceMap"), aResult);
|
||||
}
|
||||
return NS_SUCCEEDED(rv);
|
||||
}
|
||||
|
||||
static const char* kUserInteractionInactive = "user-interaction-inactive";
|
||||
static const char* kUserInteractionActive = "user-interaction-active";
|
||||
|
||||
|
|
|
@ -3082,6 +3082,16 @@ public:
|
|||
*/
|
||||
static bool IsOverridingWindowName(const nsAString& aName);
|
||||
|
||||
/**
|
||||
* If there is a SourceMap (higher precedence) or X-SourceMap (lower
|
||||
* precedence) response header in |aChannel|, set |aResult| to the
|
||||
* header's value and return true. Otherwise, return false.
|
||||
*
|
||||
* @param aChannel The HTTP channel
|
||||
* @param aResult The string result.
|
||||
*/
|
||||
static bool GetSourceMapURL(nsIHttpChannel* aChannel, nsACString& aResult);
|
||||
|
||||
private:
|
||||
static bool InitializeEventTable();
|
||||
|
||||
|
|
|
@ -136,19 +136,32 @@ GetIMEStateSetOpenName(IMEState::Open aOpen)
|
|||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
IsSameProcess(const TabParent* aTabParent1, const TabParent* aTabParent2)
|
||||
{
|
||||
if (aTabParent1 == aTabParent2) {
|
||||
return true;
|
||||
}
|
||||
if (!aTabParent1 != !aTabParent2) {
|
||||
return false;
|
||||
}
|
||||
return aTabParent1->Manager() == aTabParent2->Manager();
|
||||
}
|
||||
|
||||
StaticRefPtr<nsIContent> IMEStateManager::sContent;
|
||||
StaticRefPtr<nsPresContext> IMEStateManager::sPresContext;
|
||||
nsIWidget* IMEStateManager::sWidget = nullptr;
|
||||
nsIWidget* IMEStateManager::sFocusedIMEWidget = nullptr;
|
||||
StaticRefPtr<TabParent> IMEStateManager::sFocusedIMETabParent;
|
||||
nsIWidget* IMEStateManager::sActiveInputContextWidget = nullptr;
|
||||
StaticRefPtr<TabParent> IMEStateManager::sActiveTabParent;
|
||||
StaticRefPtr<IMEContentObserver> IMEStateManager::sActiveIMEContentObserver;
|
||||
TextCompositionArray* IMEStateManager::sTextCompositions = nullptr;
|
||||
InputContext::Origin IMEStateManager::sOrigin = InputContext::ORIGIN_MAIN;
|
||||
bool IMEStateManager::sInstalledMenuKeyboardListener = false;
|
||||
bool IMEStateManager::sIsGettingNewIMEState = false;
|
||||
bool IMEStateManager::sCheckForIMEUnawareWebApps = false;
|
||||
bool IMEStateManager::sInputModeSupported = false;
|
||||
bool IMEStateManager::sRemoteHasFocus = false;
|
||||
|
||||
// static
|
||||
void
|
||||
|
@ -163,6 +176,9 @@ IMEStateManager::Init()
|
|||
&sInputModeSupported,
|
||||
"dom.forms.inputmode",
|
||||
false);
|
||||
|
||||
sOrigin = XRE_IsParentProcess() ? InputContext::ORIGIN_MAIN :
|
||||
InputContext::ORIGIN_CONTENT;
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -222,7 +238,7 @@ IMEStateManager::StopIMEStateManagement()
|
|||
// the rights to change input context.
|
||||
|
||||
if (sTextCompositions && sPresContext) {
|
||||
NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, sPresContext);
|
||||
NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, sPresContext, sActiveTabParent);
|
||||
}
|
||||
sActiveInputContextWidget = nullptr;
|
||||
sPresContext = nullptr;
|
||||
|
@ -304,7 +320,9 @@ IMEStateManager::OnDestroyPresContext(nsPresContext* aPresContext)
|
|||
IMEState newState = GetNewIMEState(sPresContext, nullptr);
|
||||
InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
|
||||
InputContextAction::LOST_FOCUS);
|
||||
SetIMEState(newState, nullptr, sWidget, action);
|
||||
InputContext::Origin origin =
|
||||
sActiveTabParent ? InputContext::ORIGIN_CONTENT : sOrigin;
|
||||
SetIMEState(newState, nullptr, sWidget, action, origin);
|
||||
}
|
||||
sWidget = nullptr;
|
||||
sContent = nullptr;
|
||||
|
@ -359,7 +377,9 @@ IMEStateManager::OnRemoveContent(nsPresContext* aPresContext,
|
|||
IMEState newState = GetNewIMEState(sPresContext, nullptr);
|
||||
InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
|
||||
InputContextAction::LOST_FOCUS);
|
||||
SetIMEState(newState, nullptr, sWidget, action);
|
||||
InputContext::Origin origin =
|
||||
sActiveTabParent ? InputContext::ORIGIN_CONTENT : sOrigin;
|
||||
SetIMEState(newState, nullptr, sWidget, action, origin);
|
||||
}
|
||||
|
||||
sWidget = nullptr;
|
||||
|
@ -436,14 +456,47 @@ IMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
|
|||
// If we're deactivating, we shouldn't commit composition forcibly because
|
||||
// the user may want to continue the composition.
|
||||
if (aPresContext) {
|
||||
NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, oldWidget);
|
||||
NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, oldWidget, sFocusedIMETabParent);
|
||||
}
|
||||
}
|
||||
|
||||
if (sActiveIMEContentObserver &&
|
||||
(aPresContext || !sActiveIMEContentObserver->KeepAliveDuringDeactive()) &&
|
||||
!sActiveIMEContentObserver->IsManaging(aPresContext, aContent)) {
|
||||
DestroyIMEContentObserver();
|
||||
if (sActiveIMEContentObserver) {
|
||||
// If there is active IMEContentObserver, it means that focused content was
|
||||
// in this process. So, if a tab parent gets focus, it means that the
|
||||
// focused editor in this process is being blurred.
|
||||
if (newTabParent) {
|
||||
DestroyIMEContentObserver();
|
||||
}
|
||||
// If the process is being inactivated, then, IMEContentObserver should
|
||||
// stop observing the contents unless native IME requests to keep
|
||||
// composition even during deactivated.
|
||||
else if (!aPresContext) {
|
||||
if (!sActiveIMEContentObserver->KeepAliveDuringDeactive()) {
|
||||
DestroyIMEContentObserver();
|
||||
}
|
||||
}
|
||||
// Otherwise, i.e., new focused content is in this process, let's check
|
||||
// whether the new focused content is already being managed by the
|
||||
// active IME content observer.
|
||||
else if (!sActiveIMEContentObserver->IsManaging(aPresContext, aContent)) {
|
||||
DestroyIMEContentObserver();
|
||||
}
|
||||
} else {
|
||||
// If there is no active IMEContentObserver, it means that focused content
|
||||
// may be in another process.
|
||||
|
||||
// If focus is moving from current focused remote process to different
|
||||
// process while the process has IME focus too, we need to notify IME of
|
||||
// blur here because it may be too late the blur notification to reach
|
||||
// this process especially when closing active window.
|
||||
if (sFocusedIMETabParent &&
|
||||
!IsSameProcess(sFocusedIMETabParent, newTabParent)) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||
(" OnChangeFocusInternal(), notifying IME of blur of previous focused "
|
||||
"remote process because it may be too late actual notification to "
|
||||
"reach this process"));
|
||||
NotifyIME(NOTIFY_IME_OF_BLUR, sFocusedIMEWidget, sFocusedIMETabParent);
|
||||
}
|
||||
}
|
||||
|
||||
if (!aPresContext) {
|
||||
|
@ -453,11 +506,7 @@ IMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIContentParent* currentContentParent =
|
||||
sActiveTabParent ? sActiveTabParent->Manager() : nullptr;
|
||||
nsIContentParent* newContentParent =
|
||||
newTabParent ? newTabParent->Manager() : nullptr;
|
||||
if (sActiveTabParent && currentContentParent != newContentParent) {
|
||||
if (sActiveTabParent && !IsSameProcess(sActiveTabParent, newTabParent)) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||
(" OnChangeFocusInternal(), notifying previous "
|
||||
"focused child process of parent process or another child process "
|
||||
|
@ -496,23 +545,26 @@ IMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
|
|||
setIMEState = sInstalledMenuKeyboardListener;
|
||||
} else if (focusActuallyChanging) {
|
||||
InputContext context = newWidget->GetInputContext();
|
||||
if (context.mIMEState.mEnabled == IMEState::DISABLED) {
|
||||
if (context.mIMEState.mEnabled == IMEState::DISABLED &&
|
||||
context.mOrigin == InputContext::ORIGIN_CONTENT) {
|
||||
setIMEState = false;
|
||||
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||
(" OnChangeFocusInternal(), doesn't set IME "
|
||||
"state because focused element (or document) is in a child process "
|
||||
"and the IME state is already disabled"));
|
||||
"and the IME state is already disabled by a remote process"));
|
||||
} else {
|
||||
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||
(" OnChangeFocusInternal(), will disable IME "
|
||||
"until new focused element (or document) in the child process "
|
||||
"will get focus actually"));
|
||||
}
|
||||
} else {
|
||||
// When focus is NOT changed actually, we shouldn't set IME state since
|
||||
// that means that the window is being activated and the child process
|
||||
// may have composition. Then, we shouldn't commit the composition with
|
||||
// making IME state disabled.
|
||||
} else if (newWidget->GetInputContext().mOrigin !=
|
||||
InputContext::ORIGIN_CONTENT) {
|
||||
// When focus is NOT changed actually, we shouldn't set IME state if
|
||||
// current input context was set by a remote process since that means
|
||||
// that the window is being activated and the child process may have
|
||||
// composition. Then, we shouldn't commit the composition with making
|
||||
// IME state disabled.
|
||||
setIMEState = false;
|
||||
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||
(" OnChangeFocusInternal(), doesn't set IME "
|
||||
|
@ -537,7 +589,8 @@ IMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
|
|||
// Even if focus isn't changing actually, we should commit current
|
||||
// composition here since the IME state is changing.
|
||||
if (sPresContext && oldWidget && !focusActuallyChanging) {
|
||||
NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, oldWidget);
|
||||
NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, oldWidget,
|
||||
sFocusedIMETabParent);
|
||||
}
|
||||
} else if (aAction.mFocusChange == InputContextAction::FOCUS_NOT_CHANGED) {
|
||||
// If aContent isn't null or aContent is null but editable, somebody gets
|
||||
|
@ -549,7 +602,8 @@ IMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
|
|||
}
|
||||
|
||||
// Update IME state for new focus widget
|
||||
SetIMEState(newState, aContent, newWidget, aAction);
|
||||
SetIMEState(newState, aContent, newWidget, aAction,
|
||||
newTabParent ? InputContext::ORIGIN_CONTENT : sOrigin);
|
||||
}
|
||||
|
||||
sActiveTabParent = newTabParent;
|
||||
|
@ -700,7 +754,7 @@ IMEStateManager::OnClickInEditor(nsPresContext* aPresContext,
|
|||
|
||||
InputContextAction action(cause, InputContextAction::FOCUS_NOT_CHANGED);
|
||||
IMEState newState = GetNewIMEState(aPresContext, aContent);
|
||||
SetIMEState(newState, aContent, widget, action);
|
||||
SetIMEState(newState, aContent, widget, action, sOrigin);
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -894,7 +948,7 @@ IMEStateManager::UpdateIMEState(const IMEState& aNewIMEState,
|
|||
|
||||
if (updateIMEState) {
|
||||
// commit current composition before modifying IME state.
|
||||
NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, widget);
|
||||
NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, widget, sFocusedIMETabParent);
|
||||
if (NS_WARN_IF(widget->Destroyed())) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Error,
|
||||
(" UpdateIMEState(), widget has gone during committing composition"));
|
||||
|
@ -909,7 +963,7 @@ IMEStateManager::UpdateIMEState(const IMEState& aNewIMEState,
|
|||
if (updateIMEState) {
|
||||
InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
|
||||
InputContextAction::FOCUS_NOT_CHANGED);
|
||||
SetIMEState(aNewIMEState, aContent, widget, action);
|
||||
SetIMEState(aNewIMEState, aContent, widget, action, sOrigin);
|
||||
if (NS_WARN_IF(widget->Destroyed())) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Error,
|
||||
(" UpdateIMEState(), widget has gone during setting input context"));
|
||||
|
@ -1069,22 +1123,25 @@ void
|
|||
IMEStateManager::SetIMEState(const IMEState& aState,
|
||||
nsIContent* aContent,
|
||||
nsIWidget* aWidget,
|
||||
InputContextAction aAction)
|
||||
InputContextAction aAction,
|
||||
InputContext::Origin aOrigin)
|
||||
{
|
||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||
("SetIMEState(aState={ mEnabled=%s, mOpen=%s }, "
|
||||
"aContent=0x%p (TabParent=0x%p), aWidget=0x%p, aAction={ mCause=%s, "
|
||||
"mFocusChange=%s })",
|
||||
"mFocusChange=%s }, aOrigin=%s)",
|
||||
GetIMEStateEnabledName(aState.mEnabled),
|
||||
GetIMEStateSetOpenName(aState.mOpen), aContent,
|
||||
TabParent::GetFrom(aContent), aWidget,
|
||||
GetActionCauseName(aAction.mCause),
|
||||
GetActionFocusChangeName(aAction.mFocusChange)));
|
||||
GetActionFocusChangeName(aAction.mFocusChange),
|
||||
ToChar(aOrigin)));
|
||||
|
||||
NS_ENSURE_TRUE_VOID(aWidget);
|
||||
|
||||
InputContext context;
|
||||
context.mIMEState = aState;
|
||||
context.mOrigin = aOrigin;
|
||||
context.mMayBeIMEUnaware = context.mIMEState.IsEditable() &&
|
||||
sCheckForIMEUnawareWebApps && MayBeIMEUnawareWebApp(aContent);
|
||||
|
||||
|
@ -1411,25 +1468,29 @@ IMEStateManager::OnCompositionEventDiscarded(
|
|||
nsresult
|
||||
IMEStateManager::NotifyIME(IMEMessage aMessage,
|
||||
nsIWidget* aWidget,
|
||||
bool aOriginIsRemote)
|
||||
TabParent* aTabParent)
|
||||
{
|
||||
return IMEStateManager::NotifyIME(IMENotification(aMessage), aWidget,
|
||||
aOriginIsRemote);
|
||||
aTabParent);
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
IMEStateManager::NotifyIME(const IMENotification& aNotification,
|
||||
nsIWidget* aWidget,
|
||||
bool aOriginIsRemote)
|
||||
TabParent* aTabParent)
|
||||
{
|
||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||
("NotifyIME(aNotification={ mMessage=%s }, "
|
||||
"aWidget=0x%p, aOriginIsRemote=%s), sFocusedIMEWidget=0x%p, "
|
||||
"sRemoteHasFocus=%s",
|
||||
"aWidget=0x%p, aTabParent=0x%p), sFocusedIMEWidget=0x%p, "
|
||||
"sActiveTabParent=0x%p, sFocusedIMETabParent=0x%p, "
|
||||
"IsSameProcess(aTabParent, sActiveTabParent)=%s, "
|
||||
"IsSameProcess(aTabParent, sFocusedIMETabParent)=%s",
|
||||
ToChar(aNotification.mMessage), aWidget,
|
||||
GetBoolName(aOriginIsRemote), sFocusedIMEWidget,
|
||||
GetBoolName(sRemoteHasFocus)));
|
||||
aTabParent, sFocusedIMEWidget, sActiveTabParent.get(),
|
||||
sFocusedIMETabParent.get(),
|
||||
GetBoolName(IsSameProcess(aTabParent, sActiveTabParent)),
|
||||
GetBoolName(IsSameProcess(aTabParent, sFocusedIMETabParent))));
|
||||
|
||||
if (NS_WARN_IF(!aWidget)) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Error,
|
||||
|
@ -1439,61 +1500,58 @@ IMEStateManager::NotifyIME(const IMENotification& aNotification,
|
|||
|
||||
switch (aNotification.mMessage) {
|
||||
case NOTIFY_IME_OF_FOCUS: {
|
||||
// If focus notification comes from a remote process which already lost
|
||||
// focus, we shouldn't accept the focus notification. Then, following
|
||||
// notifications from the process will be ignored.
|
||||
if (NS_WARN_IF(!IsSameProcess(aTabParent, sActiveTabParent))) {
|
||||
MOZ_ASSERT(aTabParent,
|
||||
"Why was the input context initialized for a remote process but "
|
||||
"does this process get IME focus?");
|
||||
MOZ_LOG(sISMLog, LogLevel::Warning,
|
||||
(" NotifyIME(), WARNING, the received focus notification is ignored "
|
||||
"because input context was initialized for %s, perhaps, it came "
|
||||
"from a busy remote process",
|
||||
sActiveTabParent ? "another remote process" : "current process"));
|
||||
return NS_OK;
|
||||
}
|
||||
// If there is pending blur notification for current focused IME,
|
||||
// we should notify IME of blur by ourselves. Then, we should ignore
|
||||
// following notifications coming from the process.
|
||||
if (sFocusedIMEWidget) {
|
||||
if (NS_WARN_IF(!sRemoteHasFocus && !aOriginIsRemote)) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Error,
|
||||
(" NotifyIME(), although, this process is "
|
||||
"getting IME focus but there was focused IME widget"));
|
||||
} else {
|
||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||
(" NotifyIME(), tries to notify IME of "
|
||||
"blur first because remote process's blur notification hasn't "
|
||||
"been received yet..."));
|
||||
}
|
||||
MOZ_ASSERT(sFocusedIMETabParent || aTabParent,
|
||||
"This case shouldn't be caused by focus move in this process");
|
||||
nsCOMPtr<nsIWidget> focusedIMEWidget(sFocusedIMEWidget);
|
||||
sFocusedIMEWidget = nullptr;
|
||||
sRemoteHasFocus = false;
|
||||
sFocusedIMETabParent = nullptr;
|
||||
focusedIMEWidget->NotifyIME(IMENotification(NOTIFY_IME_OF_BLUR));
|
||||
}
|
||||
sRemoteHasFocus = aOriginIsRemote;
|
||||
sFocusedIMETabParent = aTabParent;
|
||||
sFocusedIMEWidget = aWidget;
|
||||
nsCOMPtr<nsIWidget> widget(aWidget);
|
||||
return widget->NotifyIME(aNotification);
|
||||
}
|
||||
case NOTIFY_IME_OF_BLUR: {
|
||||
if (!sRemoteHasFocus && aOriginIsRemote) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||
(" NotifyIME(), received blur notification "
|
||||
"after another one has focus, nothing to do..."));
|
||||
if (!IsSameProcess(aTabParent, sFocusedIMETabParent)) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Warning,
|
||||
(" NotifyIME(), WARNING, the received blur notification is ignored "
|
||||
"because it's not from current focused IME process"));
|
||||
return NS_OK;
|
||||
}
|
||||
if (NS_WARN_IF(sRemoteHasFocus && !aOriginIsRemote)) {
|
||||
if (!sFocusedIMEWidget) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Error,
|
||||
(" NotifyIME(), FAILED, received blur "
|
||||
"notification from this process but the remote has focus"));
|
||||
return NS_OK;
|
||||
}
|
||||
if (!sFocusedIMEWidget && aOriginIsRemote) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||
(" NotifyIME(), received blur notification "
|
||||
"but the remote has already lost focus"));
|
||||
return NS_OK;
|
||||
}
|
||||
if (NS_WARN_IF(!sFocusedIMEWidget)) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Error,
|
||||
(" NotifyIME(), FAILED, received blur "
|
||||
"notification but there is no focused IME widget"));
|
||||
(" NotifyIME(), WARNING, received blur notification but there is "
|
||||
"no focused IME widget"));
|
||||
return NS_OK;
|
||||
}
|
||||
if (NS_WARN_IF(sFocusedIMEWidget != aWidget)) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Error,
|
||||
(" NotifyIME(), FAILED, received blur "
|
||||
"notification but there is no focused IME widget"));
|
||||
MOZ_LOG(sISMLog, LogLevel::Warning,
|
||||
(" NotifyIME(), WARNING, the received blur notification is ignored "
|
||||
"because it's not for current focused IME widget"));
|
||||
return NS_OK;
|
||||
}
|
||||
nsCOMPtr<nsIWidget> focusedIMEWidget(sFocusedIMEWidget);
|
||||
sFocusedIMEWidget = nullptr;
|
||||
sRemoteHasFocus = false;
|
||||
sFocusedIMETabParent = nullptr;
|
||||
return focusedIMEWidget->NotifyIME(IMENotification(NOTIFY_IME_OF_BLUR));
|
||||
}
|
||||
case NOTIFY_IME_OF_SELECTION_CHANGE:
|
||||
|
@ -1501,30 +1559,22 @@ IMEStateManager::NotifyIME(const IMENotification& aNotification,
|
|||
case NOTIFY_IME_OF_POSITION_CHANGE:
|
||||
case NOTIFY_IME_OF_MOUSE_BUTTON_EVENT:
|
||||
case NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED: {
|
||||
if (!sRemoteHasFocus && aOriginIsRemote) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||
(" NotifyIME(), received content change "
|
||||
"notification from the remote but it's already lost focus"));
|
||||
return NS_OK;
|
||||
}
|
||||
if (NS_WARN_IF(sRemoteHasFocus && !aOriginIsRemote)) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Error,
|
||||
(" NotifyIME(), FAILED, received content "
|
||||
"change notification from this process but the remote has already "
|
||||
"gotten focus"));
|
||||
if (!IsSameProcess(aTabParent, sFocusedIMETabParent)) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Warning,
|
||||
(" NotifyIME(), WARNING, the received content change notification "
|
||||
"is ignored because it's not from current focused IME process"));
|
||||
return NS_OK;
|
||||
}
|
||||
if (!sFocusedIMEWidget) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||
(" NotifyIME(), received content change "
|
||||
"notification but there is no focused IME widget"));
|
||||
MOZ_LOG(sISMLog, LogLevel::Warning,
|
||||
(" NotifyIME(), WARNING, the received content change notification "
|
||||
"is ignored because there is no focused IME widget"));
|
||||
return NS_OK;
|
||||
}
|
||||
if (NS_WARN_IF(sFocusedIMEWidget != aWidget)) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Error,
|
||||
(" NotifyIME(), FAILED, received content "
|
||||
"change notification for IME which has already lost focus, so, "
|
||||
"nothing to do..."));
|
||||
MOZ_LOG(sISMLog, LogLevel::Warning,
|
||||
(" NotifyIME(), WARNING, the received content change notification "
|
||||
"is ignored because it's not for current focused IME widget"));
|
||||
return NS_OK;
|
||||
}
|
||||
nsCOMPtr<nsIWidget> widget(aWidget);
|
||||
|
@ -1536,26 +1586,35 @@ IMEStateManager::NotifyIME(const IMENotification& aNotification,
|
|||
break;
|
||||
}
|
||||
|
||||
RefPtr<TextComposition> composition;
|
||||
if (sTextCompositions) {
|
||||
composition = sTextCompositions->GetCompositionFor(aWidget);
|
||||
if (!sTextCompositions) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||
(" NotifyIME(), the request to IME is ignored because "
|
||||
"there have been no compositions yet"));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool isSynthesizedForTests =
|
||||
composition && composition->IsSynthesizedForTests();
|
||||
RefPtr<TextComposition> composition =
|
||||
sTextCompositions->GetCompositionFor(aWidget);
|
||||
if (!composition) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||
(" NotifyIME(), the request to IME is ignored because "
|
||||
"there is no active composition"));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||
(" NotifyIME(), composition=0x%p, "
|
||||
"composition->IsSynthesizedForTests()=%s",
|
||||
composition.get(), GetBoolName(isSynthesizedForTests)));
|
||||
if (!IsSameProcess(aTabParent, composition->GetTabParent())) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Warning,
|
||||
(" NotifyIME(), WARNING, the request to IME is ignored because "
|
||||
"it does not come from the remote process which has the composition "
|
||||
"on aWidget"));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
switch (aNotification.mMessage) {
|
||||
case REQUEST_TO_COMMIT_COMPOSITION:
|
||||
return composition ?
|
||||
composition->RequestToCommit(aWidget, false) : NS_OK;
|
||||
return composition->RequestToCommit(aWidget, false);
|
||||
case REQUEST_TO_CANCEL_COMPOSITION:
|
||||
return composition ?
|
||||
composition->RequestToCommit(aWidget, true) : NS_OK;
|
||||
return composition->RequestToCommit(aWidget, true);
|
||||
default:
|
||||
MOZ_CRASH("Unsupported notification");
|
||||
}
|
||||
|
@ -1568,11 +1627,11 @@ IMEStateManager::NotifyIME(const IMENotification& aNotification,
|
|||
nsresult
|
||||
IMEStateManager::NotifyIME(IMEMessage aMessage,
|
||||
nsPresContext* aPresContext,
|
||||
bool aOriginIsRemote)
|
||||
TabParent* aTabParent)
|
||||
{
|
||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||
("NotifyIME(aMessage=%s, aPresContext=0x%p, aOriginIsRemote=%s)",
|
||||
ToChar(aMessage), aPresContext, GetBoolName(aOriginIsRemote)));
|
||||
("NotifyIME(aMessage=%s, aPresContext=0x%p, aTabParent=0x%p)",
|
||||
ToChar(aMessage), aPresContext, aTabParent));
|
||||
|
||||
if (NS_WARN_IF(!CanHandleWith(aPresContext))) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
@ -1585,7 +1644,7 @@ IMEStateManager::NotifyIME(IMEMessage aMessage,
|
|||
"nsPresContext"));
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
return NotifyIME(aMessage, widget, aOriginIsRemote);
|
||||
return NotifyIME(aMessage, widget, aTabParent);
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
|
@ -58,6 +58,20 @@ public:
|
|||
return sActiveTabParent.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* DoesTabParentHaveIMEFocus() returns true when aTabParent has IME focus,
|
||||
* i.e., the TabParent sent "focus" notification but not yet sends "blur".
|
||||
* Note that this doesn't check if the remote processes are same because
|
||||
* if another TabParent has focus, committing composition causes firing
|
||||
* composition events in different TabParent. (Anyway, such case shouldn't
|
||||
* occur.)
|
||||
*/
|
||||
static bool DoesTabParentHaveIMEFocus(const TabParent* aTabParent)
|
||||
{
|
||||
MOZ_ASSERT(aTabParent);
|
||||
return sFocusedIMETabParent == aTabParent;
|
||||
}
|
||||
|
||||
/**
|
||||
* OnTabParentDestroying() is called when aTabParent is being destroyed.
|
||||
*/
|
||||
|
@ -224,13 +238,13 @@ public:
|
|||
*/
|
||||
static nsresult NotifyIME(const IMENotification& aNotification,
|
||||
nsIWidget* aWidget,
|
||||
bool aOriginIsRemote = false);
|
||||
TabParent* aTabParent = nullptr);
|
||||
static nsresult NotifyIME(IMEMessage aMessage,
|
||||
nsIWidget* aWidget,
|
||||
bool aOriginIsRemote = false);
|
||||
TabParent* aTabParent = nullptr);
|
||||
static nsresult NotifyIME(IMEMessage aMessage,
|
||||
nsPresContext* aPresContext,
|
||||
bool aOriginIsRemote = false);
|
||||
TabParent* aTabParent = nullptr);
|
||||
|
||||
static nsINode* GetRootEditableNode(nsPresContext* aPresContext,
|
||||
nsIContent* aContent);
|
||||
|
@ -248,7 +262,8 @@ protected:
|
|||
static void SetIMEState(const IMEState &aState,
|
||||
nsIContent* aContent,
|
||||
nsIWidget* aWidget,
|
||||
InputContextAction aAction);
|
||||
InputContextAction aAction,
|
||||
InputContext::Origin aOrigin);
|
||||
static void SetInputContext(nsIWidget* aWidget,
|
||||
const InputContext& aInputContext,
|
||||
const InputContextAction& aAction);
|
||||
|
@ -279,11 +294,10 @@ protected:
|
|||
// sPresContext has gone, we need to clean up some IME state on the widget
|
||||
// if the widget is available.
|
||||
static nsIWidget* sWidget;
|
||||
// sFocusedIMEWidget is, the widget which was sent to "focus" notification
|
||||
// from IMEContentObserver and not yet sent "blur" notification.
|
||||
// So, if this is not nullptr, the widget needs to receive "blur"
|
||||
// notification.
|
||||
// sFocusedIMETabParent is the tab parent, which send "focus" notification to
|
||||
// sFocusedIMEWidget (and didn't yet sent "blur" notification).
|
||||
static nsIWidget* sFocusedIMEWidget;
|
||||
static StaticRefPtr<TabParent> sFocusedIMETabParent;
|
||||
// sActiveInputContextWidget is the last widget whose SetInputContext() is
|
||||
// called. This is important to reduce sync IPC cost with parent process.
|
||||
// If IMEStateManager set input context to different widget, PuppetWidget can
|
||||
|
@ -300,11 +314,13 @@ protected:
|
|||
// something to cause committing or canceling the composition.
|
||||
static TextCompositionArray* sTextCompositions;
|
||||
|
||||
// Origin type of current process.
|
||||
static InputContext::Origin sOrigin;
|
||||
|
||||
static bool sInstalledMenuKeyboardListener;
|
||||
static bool sIsGettingNewIMEState;
|
||||
static bool sCheckForIMEUnawareWebApps;
|
||||
static bool sInputModeSupported;
|
||||
static bool sRemoteHasFocus;
|
||||
|
||||
class MOZ_STACK_CLASS GettingNewIMEStateBlocker final
|
||||
{
|
||||
|
|
|
@ -616,7 +616,7 @@ nsresult
|
|||
TextComposition::NotifyIME(IMEMessage aMessage)
|
||||
{
|
||||
NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE);
|
||||
return IMEStateManager::NotifyIME(aMessage, mPresContext);
|
||||
return IMEStateManager::NotifyIME(aMessage, mPresContext, mTabParent);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -75,6 +75,11 @@ public:
|
|||
{
|
||||
return mPresContext ? mPresContext->GetRootWidget() : nullptr;
|
||||
}
|
||||
// Returns the tab parent which has this composition in its remote process.
|
||||
TabParent* GetTabParent() const
|
||||
{
|
||||
return mTabParent;
|
||||
}
|
||||
// Returns true if the composition is started with synthesized event which
|
||||
// came from nsDOMWindowUtils.
|
||||
bool IsSynthesizedForTests() const { return mIsSynthesizedForTests; }
|
||||
|
|
|
@ -3,7 +3,7 @@ var testGenerator = testSteps();
|
|||
function* testSteps()
|
||||
{
|
||||
const name = this.window ? window.location.pathname :
|
||||
"test_storage_manager_estimate.js";
|
||||
"test_storage_manager_estimate.js";
|
||||
const objectStoreName = "storagesManager";
|
||||
const arraySize = 1e6;
|
||||
|
||||
|
|
|
@ -143,6 +143,7 @@ TabParent::TabParent(nsIContentParent* aManager,
|
|||
uint32_t aChromeFlags)
|
||||
: TabContext(aContext)
|
||||
, mFrameElement(nullptr)
|
||||
, mContentCache(*this)
|
||||
, mRect(0, 0, 0, 0)
|
||||
, mDimensions(0, 0)
|
||||
, mOrientation(0)
|
||||
|
@ -1745,7 +1746,7 @@ TabParent::RecvNotifyIMEFocus(const ContentCache& aContentCache,
|
|||
}
|
||||
|
||||
mContentCache.AssignContent(aContentCache, widget, &aIMENotification);
|
||||
IMEStateManager::NotifyIME(aIMENotification, widget, true);
|
||||
IMEStateManager::NotifyIME(aIMENotification, widget, this);
|
||||
|
||||
if (aIMENotification.mMessage == NOTIFY_IME_OF_FOCUS) {
|
||||
*aRequests = widget->IMENotificationRequestsRef();
|
||||
|
@ -1824,7 +1825,7 @@ TabParent::RecvNotifyIMEMouseButtonEvent(
|
|||
*aConsumedByIME = false;
|
||||
return IPC_OK();
|
||||
}
|
||||
nsresult rv = IMEStateManager::NotifyIME(aIMENotification, widget, true);
|
||||
nsresult rv = IMEStateManager::NotifyIME(aIMENotification, widget, this);
|
||||
*aConsumedByIME = rv == NS_SUCCESS_EVENT_CONSUMED;
|
||||
return IPC_OK();
|
||||
}
|
||||
|
|
|
@ -25,7 +25,8 @@ ADTSDecoder::Clone(MediaDecoderInit& aInit)
|
|||
MediaDecoderStateMachine*
|
||||
ADTSDecoder::CreateStateMachine()
|
||||
{
|
||||
mReader = new MediaFormatReader(this, new ADTSDemuxer(mResource));
|
||||
MediaDecoderReaderInit init(this);
|
||||
mReader = new MediaFormatReader(init, new ADTSDemuxer(mResource));
|
||||
return new MediaDecoderStateMachine(this, mReader);
|
||||
}
|
||||
|
||||
|
|
|
@ -339,45 +339,46 @@ DecoderTraits::CreateDecoder(MediaDecoderInit& aInit,
|
|||
/* static */
|
||||
MediaDecoderReader*
|
||||
DecoderTraits::CreateReader(const MediaContainerType& aType,
|
||||
AbstractMediaDecoder* aDecoder,
|
||||
MediaResource* aResource)
|
||||
const MediaDecoderReaderInit& aInit)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MediaDecoderReader* decoderReader = nullptr;
|
||||
|
||||
if (!aDecoder) {
|
||||
if (!aInit.mDecoder) {
|
||||
return decoderReader;
|
||||
}
|
||||
|
||||
MediaResource* resource = aInit.mResource;
|
||||
|
||||
#ifdef MOZ_FMP4
|
||||
if (MP4Decoder::IsSupportedType(aType,
|
||||
/* DecoderDoctorDiagnostics* */ nullptr)) {
|
||||
decoderReader = new MediaFormatReader(aDecoder, new MP4Demuxer(aResource));
|
||||
decoderReader = new MediaFormatReader(aInit, new MP4Demuxer(resource));
|
||||
} else
|
||||
#endif
|
||||
if (MP3Decoder::IsSupportedType(aType)) {
|
||||
decoderReader = new MediaFormatReader(aDecoder, new MP3Demuxer(aResource));
|
||||
decoderReader = new MediaFormatReader(aInit, new MP3Demuxer(resource));
|
||||
} else
|
||||
if (ADTSDecoder::IsSupportedType(aType)) {
|
||||
decoderReader = new MediaFormatReader(aDecoder, new ADTSDemuxer(aResource));
|
||||
decoderReader = new MediaFormatReader(aInit, new ADTSDemuxer(resource));
|
||||
} else
|
||||
if (WaveDecoder::IsSupportedType(aType)) {
|
||||
decoderReader = new MediaFormatReader(aDecoder, new WAVDemuxer(aResource));
|
||||
decoderReader = new MediaFormatReader(aInit, new WAVDemuxer(resource));
|
||||
} else
|
||||
if (FlacDecoder::IsSupportedType(aType)) {
|
||||
decoderReader = new MediaFormatReader(aDecoder, new FlacDemuxer(aResource));
|
||||
decoderReader = new MediaFormatReader(aInit, new FlacDemuxer(resource));
|
||||
} else
|
||||
if (OggDecoder::IsSupportedType(aType)) {
|
||||
decoderReader = new MediaFormatReader(aDecoder, new OggDemuxer(aResource));
|
||||
decoderReader = new MediaFormatReader(aInit, new OggDemuxer(resource));
|
||||
} else
|
||||
#ifdef MOZ_ANDROID_OMX
|
||||
if (MediaDecoder::IsAndroidMediaPluginEnabled() &&
|
||||
EnsureAndroidMediaPluginHost()->FindDecoder(aType, nullptr)) {
|
||||
decoderReader = new AndroidMediaReader(aDecoder, aType, aResource);
|
||||
decoderReader = new AndroidMediaReader(aType, aInit);
|
||||
} else
|
||||
#endif
|
||||
if (WebMDecoder::IsSupportedType(aType)) {
|
||||
decoderReader = new MediaFormatReader(aDecoder, new WebMDemuxer(aResource));
|
||||
decoderReader = new MediaFormatReader(aInit, new WebMDemuxer(resource));
|
||||
}
|
||||
|
||||
return decoderReader;
|
||||
|
|
|
@ -19,6 +19,7 @@ class ChannelMediaDecoder;
|
|||
class DecoderDoctorDiagnostics;
|
||||
class MediaContainerType;
|
||||
struct MediaDecoderInit;
|
||||
struct MediaDecoderReaderInit;
|
||||
class MediaDecoderOwner;
|
||||
class MediaDecoderReader;
|
||||
class MediaResource;
|
||||
|
@ -51,8 +52,7 @@ public:
|
|||
// Create a reader for thew given MIME type aType. Returns null
|
||||
// if we were unable to create the reader.
|
||||
static MediaDecoderReader* CreateReader(const MediaContainerType& aType,
|
||||
AbstractMediaDecoder* aDecoder,
|
||||
MediaResource* aResource);
|
||||
const MediaDecoderReaderInit& aInit);
|
||||
|
||||
// Returns true if MIME type aType is supported in video documents,
|
||||
// or false otherwise. Not all platforms support all MIME types, and
|
||||
|
|
|
@ -741,11 +741,63 @@ static int32_t GetMaxBlocks()
|
|||
{
|
||||
// We look up the cache size every time. This means dynamic changes
|
||||
// to the pref are applied.
|
||||
// Cache size is in KB
|
||||
int32_t cacheSize = Preferences::GetInt("media.cache_size", 500*1024);
|
||||
int64_t maxBlocks = static_cast<int64_t>(cacheSize)*1024/MediaCache::BLOCK_SIZE;
|
||||
maxBlocks = std::max<int64_t>(maxBlocks, 1);
|
||||
return int32_t(std::min<int64_t>(maxBlocks, INT32_MAX));
|
||||
const uint32_t cacheSizeKb =
|
||||
std::min(MediaPrefs::MediaCacheSizeKb(), uint32_t(INT32_MAX) * 2);
|
||||
// Ensure we can divide BLOCK_SIZE by 1024.
|
||||
static_assert(MediaCache::BLOCK_SIZE % 1024 == 0,
|
||||
"BLOCK_SIZE should be a multiple of 1024");
|
||||
// Ensure BLOCK_SIZE/1024 is at least 2.
|
||||
static_assert(MediaCache::BLOCK_SIZE / 1024 >= 2,
|
||||
"BLOCK_SIZE / 1024 should be at least 2");
|
||||
// Ensure we can convert BLOCK_SIZE/1024 to a uint32_t without truncation.
|
||||
static_assert(MediaCache::BLOCK_SIZE / 1024 <= int64_t(UINT32_MAX),
|
||||
"BLOCK_SIZE / 1024 should be at most UINT32_MAX");
|
||||
// Since BLOCK_SIZE is a strict multiple of 1024,
|
||||
// cacheSizeKb * 1024 / BLOCK_SIZE == cacheSizeKb / (BLOCK_SIZE / 1024),
|
||||
// but the latter formula avoids a potential overflow from `* 1024`.
|
||||
// And because BLOCK_SIZE/1024 is at least 2, the maximum cache size
|
||||
// INT32_MAX*2 will give a maxBlocks that can fit in an int32_t.
|
||||
constexpr uint32_t blockSizeKb = uint32_t(MediaCache::BLOCK_SIZE / 1024);
|
||||
const int32_t maxBlocks = int32_t(cacheSizeKb / blockSizeKb);
|
||||
return std::max(maxBlocks, int32_t(1));
|
||||
}
|
||||
|
||||
// Allowed range is whatever can be accessed with an int32_t block index.
|
||||
static bool
|
||||
IsOffsetAllowed(int64_t aOffset)
|
||||
{
|
||||
return aOffset < (int64_t(INT32_MAX) + 1) * MediaCache::BLOCK_SIZE &&
|
||||
aOffset >= 0;
|
||||
}
|
||||
|
||||
// Convert 64-bit offset to 32-bit block index.
|
||||
// Assumes offset range-check was already done.
|
||||
static int32_t
|
||||
OffsetToBlockIndexUnchecked(int64_t aOffset)
|
||||
{
|
||||
// Still check for allowed range in debug builds, to catch out-of-range
|
||||
// issues early during development.
|
||||
MOZ_ASSERT(IsOffsetAllowed(aOffset));
|
||||
return int32_t(aOffset / MediaCache::BLOCK_SIZE);
|
||||
}
|
||||
|
||||
// Convert 64-bit offset to 32-bit block index. -1 if out of allowed range.
|
||||
static int32_t
|
||||
OffsetToBlockIndex(int64_t aOffset)
|
||||
{
|
||||
return IsOffsetAllowed(aOffset) ? OffsetToBlockIndexUnchecked(aOffset) : -1;
|
||||
}
|
||||
|
||||
// Convert 64-bit offset to 32-bit offset inside a block.
|
||||
// Will not fail (even if offset is outside allowed range), so there is no
|
||||
// need to check for errors.
|
||||
static int32_t
|
||||
OffsetInBlock(int64_t aOffset)
|
||||
{
|
||||
// Still check for allowed range in debug builds, to catch out-of-range
|
||||
// issues early during development.
|
||||
MOZ_ASSERT(IsOffsetAllowed(aOffset));
|
||||
return int32_t(aOffset % MediaCache::BLOCK_SIZE);
|
||||
}
|
||||
|
||||
int32_t
|
||||
|
@ -754,8 +806,11 @@ MediaCache::FindBlockForIncomingData(TimeStamp aNow,
|
|||
{
|
||||
mReentrantMonitor.AssertCurrentThreadIn();
|
||||
|
||||
int32_t blockIndex = FindReusableBlock(aNow, aStream,
|
||||
aStream->mChannelOffset/BLOCK_SIZE, INT32_MAX);
|
||||
int32_t blockIndex =
|
||||
FindReusableBlock(aNow,
|
||||
aStream,
|
||||
OffsetToBlockIndexUnchecked(aStream->mChannelOffset),
|
||||
INT32_MAX);
|
||||
|
||||
if (blockIndex < 0 || !IsBlockFree(blockIndex)) {
|
||||
// The block returned is already allocated.
|
||||
|
@ -784,7 +839,8 @@ MediaCache::BlockIsReusable(int32_t aBlockIndex)
|
|||
for (uint32_t i = 0; i < block->mOwners.Length(); ++i) {
|
||||
MediaCacheStream* stream = block->mOwners[i].mStream;
|
||||
if (stream->mPinCount > 0 ||
|
||||
stream->mStreamOffset/BLOCK_SIZE == block->mOwners[i].mStreamBlock) {
|
||||
uint32_t(OffsetToBlockIndex(stream->mStreamOffset)) ==
|
||||
block->mOwners[i].mStreamBlock) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1327,14 +1383,17 @@ MediaCache::Update()
|
|||
if (enableReading) {
|
||||
for (uint32_t j = 0; j < i; ++j) {
|
||||
MediaCacheStream* other = mStreams[j];
|
||||
if (other->mResourceID == stream->mResourceID &&
|
||||
!other->mClosed && !other->mClient->IsSuspended() &&
|
||||
other->mChannelOffset/BLOCK_SIZE == desiredOffset/BLOCK_SIZE) {
|
||||
if (other->mResourceID == stream->mResourceID && !other->mClosed &&
|
||||
!other->mClient->IsSuspended() &&
|
||||
OffsetToBlockIndexUnchecked(other->mChannelOffset) ==
|
||||
OffsetToBlockIndexUnchecked(desiredOffset)) {
|
||||
// This block is already going to be read by the other stream.
|
||||
// So don't try to read it from this stream as well.
|
||||
enableReading = false;
|
||||
LOG("Stream %p waiting on same block (%" PRId64 ") from stream %p",
|
||||
stream, desiredOffset/BLOCK_SIZE, other);
|
||||
LOG("Stream %p waiting on same block (%" PRId32 ") from stream %p",
|
||||
stream,
|
||||
OffsetToBlockIndexUnchecked(desiredOffset),
|
||||
other);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1347,7 +1406,8 @@ MediaCache::Update()
|
|||
// Round seek offset down to the start of the block. This is essential
|
||||
// because we don't want to think we have part of a block already
|
||||
// in mPartialBlockBuffer.
|
||||
stream->mChannelOffset = (desiredOffset/BLOCK_SIZE)*BLOCK_SIZE;
|
||||
stream->mChannelOffset =
|
||||
OffsetToBlockIndexUnchecked(desiredOffset) * BLOCK_SIZE;
|
||||
actions[i] = stream->mCacheSuspended ? SEEK_AND_RESUME : SEEK;
|
||||
} else if (enableReading && stream->mCacheSuspended) {
|
||||
actions[i] = RESUME;
|
||||
|
@ -1550,7 +1610,8 @@ MediaCache::AllocateAndWriteBlock(
|
|||
{
|
||||
mReentrantMonitor.AssertCurrentThreadIn();
|
||||
|
||||
int32_t streamBlockIndex = aStream->mChannelOffset/BLOCK_SIZE;
|
||||
int32_t streamBlockIndex =
|
||||
OffsetToBlockIndexUnchecked(aStream->mChannelOffset);
|
||||
|
||||
// Remove all cached copies of this block
|
||||
ResourceStreamIterator iter(this, aStream->mResourceID);
|
||||
|
@ -1749,10 +1810,16 @@ MediaCache::NoteSeek(MediaCacheStream* aStream, int64_t aOldOffset)
|
|||
// We seeked forward. Convert blocks from readahead to played.
|
||||
// Any readahead block that intersects the seeked-over range must
|
||||
// be converted.
|
||||
int32_t blockIndex = aOldOffset/BLOCK_SIZE;
|
||||
int32_t blockIndex = OffsetToBlockIndex(aOldOffset);
|
||||
if (blockIndex < 0) {
|
||||
return;
|
||||
}
|
||||
int32_t endIndex =
|
||||
std::min<int64_t>((aStream->mStreamOffset + BLOCK_SIZE - 1)/BLOCK_SIZE,
|
||||
aStream->mBlocks.Length());
|
||||
std::min(OffsetToBlockIndex(aStream->mStreamOffset + (BLOCK_SIZE - 1)),
|
||||
int32_t(aStream->mBlocks.Length()));
|
||||
if (endIndex < 0) {
|
||||
return;
|
||||
}
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
while (blockIndex < endIndex) {
|
||||
int32_t cacheBlockIndex = aStream->mBlocks[blockIndex];
|
||||
|
@ -1769,10 +1836,16 @@ MediaCache::NoteSeek(MediaCacheStream* aStream, int64_t aOldOffset)
|
|||
// Any played block that is entirely after the start of the seeked-over
|
||||
// range must be converted.
|
||||
int32_t blockIndex =
|
||||
(aStream->mStreamOffset + BLOCK_SIZE - 1)/BLOCK_SIZE;
|
||||
OffsetToBlockIndex(aStream->mStreamOffset + (BLOCK_SIZE - 1));
|
||||
if (blockIndex < 0) {
|
||||
return;
|
||||
}
|
||||
int32_t endIndex =
|
||||
std::min<int64_t>((aOldOffset + BLOCK_SIZE - 1)/BLOCK_SIZE,
|
||||
aStream->mBlocks.Length());
|
||||
std::min(OffsetToBlockIndex(aOldOffset + (BLOCK_SIZE - 1)),
|
||||
int32_t(aStream->mBlocks.Length()));
|
||||
if (endIndex < 0) {
|
||||
return;
|
||||
}
|
||||
while (blockIndex < endIndex) {
|
||||
MOZ_ASSERT(endIndex > 0);
|
||||
int32_t cacheBlockIndex = aStream->mBlocks[endIndex - 1];
|
||||
|
@ -1860,7 +1933,7 @@ MediaCacheStream::NotifyDataReceived(int64_t aSize, const char* aData,
|
|||
|
||||
// We process the data one block (or part of a block) at a time
|
||||
while (size > 0) {
|
||||
uint32_t blockIndex = mChannelOffset/BLOCK_SIZE;
|
||||
uint32_t blockIndex = OffsetToBlockIndexUnchecked(mChannelOffset);
|
||||
int32_t blockOffset = int32_t(mChannelOffset - blockIndex*BLOCK_SIZE);
|
||||
int32_t chunkSize = std::min<int64_t>(BLOCK_SIZE - blockOffset, size);
|
||||
|
||||
|
@ -1910,7 +1983,7 @@ MediaCacheStream::FlushPartialBlockInternal(bool aNotifyAll,
|
|||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
||||
|
||||
int32_t blockOffset = int32_t(mChannelOffset%BLOCK_SIZE);
|
||||
int32_t blockOffset = OffsetInBlock(mChannelOffset);
|
||||
if (blockOffset > 0) {
|
||||
LOG("Stream %p writing partial block: [%d] bytes; "
|
||||
"mStreamOffset [%" PRId64 "] mChannelOffset[%"
|
||||
|
@ -2155,13 +2228,15 @@ int64_t
|
|||
MediaCacheStream::GetCachedDataEndInternal(int64_t aOffset)
|
||||
{
|
||||
mMediaCache->GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
uint32_t startBlockIndex = aOffset/BLOCK_SIZE;
|
||||
uint32_t blockIndex = startBlockIndex;
|
||||
while (blockIndex < mBlocks.Length() && mBlocks[blockIndex] != -1) {
|
||||
int32_t blockIndex = OffsetToBlockIndex(aOffset);
|
||||
if (blockIndex < 0) {
|
||||
return aOffset;
|
||||
}
|
||||
while (size_t(blockIndex) < mBlocks.Length() && mBlocks[blockIndex] != -1) {
|
||||
++blockIndex;
|
||||
}
|
||||
int64_t result = blockIndex*BLOCK_SIZE;
|
||||
if (blockIndex == mChannelOffset/BLOCK_SIZE) {
|
||||
if (blockIndex == OffsetToBlockIndexUnchecked(mChannelOffset)) {
|
||||
// The block containing mChannelOffset may be partially read but not
|
||||
// yet committed to the main cache
|
||||
result = mChannelOffset;
|
||||
|
@ -2181,8 +2256,11 @@ MediaCacheStream::GetNextCachedDataInternal(int64_t aOffset)
|
|||
if (aOffset == mStreamLength)
|
||||
return -1;
|
||||
|
||||
uint32_t startBlockIndex = aOffset/BLOCK_SIZE;
|
||||
uint32_t channelBlockIndex = mChannelOffset/BLOCK_SIZE;
|
||||
int32_t startBlockIndex = OffsetToBlockIndex(aOffset);
|
||||
if (startBlockIndex < 0) {
|
||||
return -1;
|
||||
}
|
||||
int32_t channelBlockIndex = OffsetToBlockIndexUnchecked(mChannelOffset);
|
||||
|
||||
if (startBlockIndex == channelBlockIndex &&
|
||||
aOffset < mChannelOffset) {
|
||||
|
@ -2192,7 +2270,7 @@ MediaCacheStream::GetNextCachedDataInternal(int64_t aOffset)
|
|||
return aOffset;
|
||||
}
|
||||
|
||||
if (startBlockIndex >= mBlocks.Length())
|
||||
if (size_t(startBlockIndex) >= mBlocks.Length())
|
||||
return -1;
|
||||
|
||||
// Is the current block cached?
|
||||
|
@ -2200,18 +2278,18 @@ MediaCacheStream::GetNextCachedDataInternal(int64_t aOffset)
|
|||
return aOffset;
|
||||
|
||||
// Count the number of uncached blocks
|
||||
bool hasPartialBlock = (mChannelOffset % BLOCK_SIZE) != 0;
|
||||
uint32_t blockIndex = startBlockIndex + 1;
|
||||
bool hasPartialBlock = OffsetInBlock(mChannelOffset) != 0;
|
||||
int32_t blockIndex = startBlockIndex + 1;
|
||||
while (true) {
|
||||
if ((hasPartialBlock && blockIndex == channelBlockIndex) ||
|
||||
(blockIndex < mBlocks.Length() && mBlocks[blockIndex] != -1)) {
|
||||
(size_t(blockIndex) < mBlocks.Length() && mBlocks[blockIndex] != -1)) {
|
||||
// We at the incoming channel block, which has has data in it,
|
||||
// or are we at a cached block. Return index of block start.
|
||||
return blockIndex * BLOCK_SIZE;
|
||||
}
|
||||
|
||||
// No more cached blocks?
|
||||
if (blockIndex >= mBlocks.Length())
|
||||
if (size_t(blockIndex) >= mBlocks.Length())
|
||||
return -1;
|
||||
|
||||
++blockIndex;
|
||||
|
@ -2270,8 +2348,9 @@ MediaCacheStream::Seek(int32_t aWhence, int64_t aOffset)
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (newOffset < 0)
|
||||
if (!IsOffsetAllowed(newOffset)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mStreamOffset = newOffset;
|
||||
|
||||
LOG("Stream %p Seek to %" PRId64, this, mStreamOffset);
|
||||
|
@ -2316,7 +2395,10 @@ MediaCacheStream::Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes)
|
|||
uint32_t count = 0;
|
||||
// Read one block (or part of a block) at a time
|
||||
while (count < aCount) {
|
||||
uint32_t streamBlock = uint32_t(streamOffset/BLOCK_SIZE);
|
||||
int32_t streamBlock = OffsetToBlockIndex(streamOffset);
|
||||
if (streamBlock < 0) {
|
||||
break;
|
||||
}
|
||||
uint32_t offsetInStreamBlock = uint32_t(streamOffset - streamBlock*BLOCK_SIZE);
|
||||
int64_t size = std::min<int64_t>(aCount - count, BLOCK_SIZE - offsetInStreamBlock);
|
||||
|
||||
|
@ -2332,7 +2414,8 @@ MediaCacheStream::Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes)
|
|||
size = std::min(size, int64_t(INT32_MAX));
|
||||
}
|
||||
|
||||
int32_t cacheBlock = streamBlock < mBlocks.Length() ? mBlocks[streamBlock] : -1;
|
||||
int32_t cacheBlock =
|
||||
size_t(streamBlock) < mBlocks.Length() ? mBlocks[streamBlock] : -1;
|
||||
if (cacheBlock < 0) {
|
||||
// We don't have a complete cached block here.
|
||||
|
||||
|
@ -2349,7 +2432,8 @@ MediaCacheStream::Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes)
|
|||
MediaCacheStream* streamWithPartialBlock = nullptr;
|
||||
MediaCache::ResourceStreamIterator iter(mMediaCache, mResourceID);
|
||||
while (MediaCacheStream* stream = iter.Next()) {
|
||||
if (uint32_t(stream->mChannelOffset/BLOCK_SIZE) == streamBlock &&
|
||||
if (OffsetToBlockIndexUnchecked(stream->mChannelOffset) ==
|
||||
streamBlock &&
|
||||
streamOffset < stream->mChannelOffset) {
|
||||
streamWithPartialBlock = stream;
|
||||
break;
|
||||
|
@ -2438,7 +2522,10 @@ MediaCacheStream::ReadFromCache(char* aBuffer, int64_t aOffset, int64_t aCount)
|
|||
// after calling |mMediaCache->ReadCacheFile|.
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
uint32_t streamBlock = uint32_t(streamOffset/BLOCK_SIZE);
|
||||
int32_t streamBlock = OffsetToBlockIndex(streamOffset);
|
||||
if (streamBlock < 0) {
|
||||
break;
|
||||
}
|
||||
uint32_t offsetInStreamBlock =
|
||||
uint32_t(streamOffset - streamBlock*BLOCK_SIZE);
|
||||
int64_t size = std::min<int64_t>(aCount - count, BLOCK_SIZE - offsetInStreamBlock);
|
||||
|
@ -2455,8 +2542,9 @@ MediaCacheStream::ReadFromCache(char* aBuffer, int64_t aOffset, int64_t aCount)
|
|||
}
|
||||
|
||||
int32_t bytes;
|
||||
uint32_t channelBlock = uint32_t(mChannelOffset/BLOCK_SIZE);
|
||||
int32_t cacheBlock = streamBlock < mBlocks.Length() ? mBlocks[streamBlock] : -1;
|
||||
int32_t channelBlock = OffsetToBlockIndexUnchecked(mChannelOffset);
|
||||
int32_t cacheBlock =
|
||||
size_t(streamBlock) < mBlocks.Length() ? mBlocks[streamBlock] : -1;
|
||||
if (channelBlock == streamBlock && streamOffset < mChannelOffset) {
|
||||
// We can just use the data in mPartialBlockBuffer. In fact we should
|
||||
// use it rather than waiting for the block to fill and land in
|
||||
|
|
|
@ -68,10 +68,9 @@ public:
|
|||
size_t mSize;
|
||||
};
|
||||
|
||||
MediaDecoderReader::MediaDecoderReader(AbstractMediaDecoder* aDecoder,
|
||||
MediaResource* aResource)
|
||||
MediaDecoderReader::MediaDecoderReader(const MediaDecoderReaderInit& aInit)
|
||||
: mAudioCompactor(mAudioQueue)
|
||||
, mDecoder(aDecoder)
|
||||
, mDecoder(aInit.mDecoder)
|
||||
, mTaskQueue(new TaskQueue(
|
||||
GetMediaThreadPool(MediaThreadType::PLAYBACK),
|
||||
"MediaDecoderReader::mTaskQueue",
|
||||
|
@ -82,7 +81,7 @@ MediaDecoderReader::MediaDecoderReader(AbstractMediaDecoder* aDecoder,
|
|||
, mIgnoreAudioOutputFormat(false)
|
||||
, mHitAudioDecodeError(false)
|
||||
, mShutdown(false)
|
||||
, mResource(aResource)
|
||||
, mResource(aInit.mResource)
|
||||
{
|
||||
MOZ_COUNT_CTOR(MediaDecoderReader);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
|
|
@ -26,6 +26,7 @@ namespace mozilla {
|
|||
class CDMProxy;
|
||||
class MediaDecoderReader;
|
||||
class TaskQueue;
|
||||
class VideoFrameContainer;
|
||||
|
||||
struct WaitForDataRejectValue
|
||||
{
|
||||
|
@ -61,6 +62,18 @@ struct MetadataHolder
|
|||
UniquePtr<MetadataTags> mTags;
|
||||
};
|
||||
|
||||
struct MOZ_STACK_CLASS MediaDecoderReaderInit
|
||||
{
|
||||
AbstractMediaDecoder* const mDecoder;
|
||||
MediaResource* mResource = nullptr;
|
||||
VideoFrameContainer* mVideoFrameContainer = nullptr;
|
||||
|
||||
explicit MediaDecoderReaderInit(AbstractMediaDecoder* aDecoder)
|
||||
: mDecoder(aDecoder)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Encapsulates the decoding and reading of media data. Reading can either
|
||||
// synchronous and done on the calling "decode" thread, or asynchronous and
|
||||
// performed on a background thread, with the result being returned by
|
||||
|
@ -97,8 +110,7 @@ public:
|
|||
|
||||
// The caller must ensure that Shutdown() is called before aDecoder is
|
||||
// destroyed.
|
||||
explicit MediaDecoderReader(AbstractMediaDecoder* aDecoder,
|
||||
MediaResource* aResource = nullptr);
|
||||
explicit MediaDecoderReader(const MediaDecoderReaderInit& aInit);
|
||||
|
||||
// Initializes the reader, returns NS_OK on success, or NS_ERROR_FAILURE
|
||||
// on failure.
|
||||
|
|
|
@ -1094,10 +1094,9 @@ MediaFormatReader::DemuxerProxy::NotifyDataArrived()
|
|||
});
|
||||
}
|
||||
|
||||
MediaFormatReader::MediaFormatReader(AbstractMediaDecoder* aDecoder,
|
||||
MediaDataDemuxer* aDemuxer,
|
||||
VideoFrameContainer* aVideoFrameContainer)
|
||||
: MediaDecoderReader(aDecoder)
|
||||
MediaFormatReader::MediaFormatReader(const MediaDecoderReaderInit& aInit,
|
||||
MediaDataDemuxer* aDemuxer)
|
||||
: MediaDecoderReader(aInit)
|
||||
, mAudio(this, MediaData::AUDIO_DATA,
|
||||
MediaPrefs::MaxAudioDecodeError())
|
||||
, mVideo(this, MediaData::VIDEO_DATA,
|
||||
|
@ -1110,17 +1109,17 @@ MediaFormatReader::MediaFormatReader(AbstractMediaDecoder* aDecoder,
|
|||
, mInitDone(false)
|
||||
, mTrackDemuxersMayBlock(false)
|
||||
, mSeekScheduled(false)
|
||||
, mVideoFrameContainer(aVideoFrameContainer)
|
||||
, mVideoFrameContainer(aInit.mVideoFrameContainer)
|
||||
, mDecoderFactory(new DecoderFactory(this))
|
||||
, mShutdownPromisePool(new ShutdownPromisePool())
|
||||
{
|
||||
MOZ_ASSERT(aDemuxer);
|
||||
MOZ_COUNT_CTOR(MediaFormatReader);
|
||||
|
||||
if (aDecoder && aDecoder->CompositorUpdatedEvent()) {
|
||||
mCompositorUpdatedListener =
|
||||
aDecoder->CompositorUpdatedEvent()->Connect(
|
||||
mTaskQueue, this, &MediaFormatReader::NotifyCompositorUpdated);
|
||||
AbstractMediaDecoder* decoder = aInit.mDecoder;
|
||||
if (decoder && decoder->CompositorUpdatedEvent()) {
|
||||
mCompositorUpdatedListener = decoder->CompositorUpdatedEvent()->Connect(
|
||||
mTaskQueue, this, &MediaFormatReader::NotifyCompositorUpdated);
|
||||
}
|
||||
mOnTrackWaitingForKeyListener = OnTrackWaitingForKey().Connect(
|
||||
mTaskQueue, this, &MediaFormatReader::NotifyWaitingForKey);
|
||||
|
|
|
@ -29,9 +29,7 @@ class MediaFormatReader final : public MediaDecoderReader
|
|||
typedef MozPromise<bool, MediaResult, /* IsExclusive = */ true> NotifyDataArrivedPromise;
|
||||
|
||||
public:
|
||||
MediaFormatReader(AbstractMediaDecoder* aDecoder,
|
||||
MediaDataDemuxer* aDemuxer,
|
||||
VideoFrameContainer* aVideoFrameContainer = nullptr);
|
||||
MediaFormatReader(const MediaDecoderReaderInit& aInit, MediaDataDemuxer* aDemuxer);
|
||||
|
||||
virtual ~MediaFormatReader();
|
||||
|
||||
|
|
|
@ -87,6 +87,7 @@ private:
|
|||
// This is where DECL_MEDIA_PREF for each of the preferences should go.
|
||||
|
||||
// Cache sizes.
|
||||
DECL_MEDIA_PREF("media.cache_size", MediaCacheSizeKb, uint32_t, 512000);
|
||||
DECL_MEDIA_PREF("media.memory_cache_max_size", MediaMemoryCacheMaxSize, uint32_t, 8192);
|
||||
DECL_MEDIA_PREF("media.memory_caches_combined_limit_kb", MediaMemoryCachesCombinedLimitKb, uint32_t, 524288);
|
||||
DECL_MEDIA_PREF("media.memory_caches_combined_limit_pc_sysmem",
|
||||
|
|
|
@ -19,7 +19,9 @@ AndroidMediaDecoder::AndroidMediaDecoder(MediaDecoderInit& aInit,
|
|||
|
||||
MediaDecoderStateMachine* AndroidMediaDecoder::CreateStateMachine()
|
||||
{
|
||||
mReader = new AndroidMediaReader(this, mType, mResource);
|
||||
MediaDecoderReaderInit init(this);
|
||||
init.mResource = mResource;
|
||||
mReader = new AndroidMediaReader(mType, init);
|
||||
return new MediaDecoderStateMachine(this, mReader);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,10 +25,9 @@ using namespace mozilla::media;
|
|||
typedef mozilla::layers::Image Image;
|
||||
typedef mozilla::layers::PlanarYCbCrImage PlanarYCbCrImage;
|
||||
|
||||
AndroidMediaReader::AndroidMediaReader(AbstractMediaDecoder *aDecoder,
|
||||
const MediaContainerType& aContainerType,
|
||||
MediaResource* aResource) :
|
||||
MediaDecoderReader(aDecoder, aResource),
|
||||
AndroidMediaReader::AndroidMediaReader(const MediaContainerType& aContainerType,
|
||||
const MediaDecoderReaderInit& aInit) :
|
||||
MediaDecoderReader(aInit),
|
||||
mType(aContainerType),
|
||||
mPlugin(nullptr),
|
||||
mHasAudio(false),
|
||||
|
|
|
@ -37,9 +37,8 @@ class AndroidMediaReader : public MediaDecoderReader
|
|||
MozPromiseHolder<MediaDecoderReader::SeekPromise> mSeekPromise;
|
||||
MozPromiseRequestHolder<MediaDecoderReader::VideoDataPromise> mSeekRequest;
|
||||
public:
|
||||
AndroidMediaReader(AbstractMediaDecoder* aDecoder,
|
||||
const MediaContainerType& aContainerType,
|
||||
MediaResource* aResource);
|
||||
AndroidMediaReader(const MediaContainerType& aContainerType,
|
||||
const MediaDecoderReaderInit& aInit);
|
||||
|
||||
nsresult ResetDecode(TrackSet aTracks = TrackSet(TrackInfo::kAudioTrack,
|
||||
TrackInfo::kVideoTrack)) override;
|
||||
|
|
|
@ -26,7 +26,8 @@ FlacDecoder::Clone(MediaDecoderInit& aInit)
|
|||
MediaDecoderStateMachine*
|
||||
FlacDecoder::CreateStateMachine()
|
||||
{
|
||||
mReader = new MediaFormatReader(this, new FlacDemuxer(mResource));
|
||||
MediaDecoderReaderInit init(this);
|
||||
mReader = new MediaFormatReader(init, new FlacDemuxer(mResource));
|
||||
return new MediaDecoderStateMachine(this, mReader);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,9 +32,9 @@ MP4Decoder::MP4Decoder(MediaDecoderInit& aInit)
|
|||
|
||||
MediaDecoderStateMachine* MP4Decoder::CreateStateMachine()
|
||||
{
|
||||
mReader = new MediaFormatReader(
|
||||
this, new MP4Demuxer(mResource), GetVideoFrameContainer());
|
||||
|
||||
MediaDecoderReaderInit init(this);
|
||||
init.mVideoFrameContainer = GetVideoFrameContainer();
|
||||
mReader = new MediaFormatReader(init, new MP4Demuxer(mResource));
|
||||
return new MediaDecoderStateMachine(this, mReader);
|
||||
}
|
||||
|
||||
|
|
|
@ -520,7 +520,8 @@ MP4TrackDemuxer::GetSamples(int32_t aNumSamples)
|
|||
}
|
||||
for (const auto& sample : samples->mSamples) {
|
||||
// Collect telemetry from h264 Annex B SPS.
|
||||
if (mNeedSPSForTelemetry) {
|
||||
if (mNeedSPSForTelemetry && mIsH264 &&
|
||||
mp4_demuxer::AnnexB::IsAVCC(sample)) {
|
||||
RefPtr<MediaByteBuffer> extradata =
|
||||
mp4_demuxer::H264::ExtractExtraData(sample);
|
||||
if (mp4_demuxer::H264::HasSPS(extradata)) {
|
||||
|
|
|
@ -28,10 +28,10 @@ HLSDecoder::CreateStateMachine()
|
|||
MOZ_ASSERT(resource);
|
||||
auto resourceWrapper = static_cast<HLSResource*>(resource)->GetResourceWrapper();
|
||||
MOZ_ASSERT(resourceWrapper);
|
||||
MediaDecoderReaderInit init(this);
|
||||
init.mVideoFrameContainer = GetVideoFrameContainer();
|
||||
mReader =
|
||||
new MediaFormatReader(this,
|
||||
new HLSDemuxer(resourceWrapper->GetPlayerId()),
|
||||
GetVideoFrameContainer());
|
||||
new MediaFormatReader(init, new HLSDemuxer(resourceWrapper->GetPlayerId()));
|
||||
|
||||
return new MediaDecoderStateMachine(this, mReader);
|
||||
}
|
||||
|
|
|
@ -39,7 +39,9 @@ MediaSourceDecoder::CreateStateMachine()
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mDemuxer = new MediaSourceDemuxer(AbstractMainThread());
|
||||
mReader = new MediaFormatReader(this, mDemuxer, GetVideoFrameContainer());
|
||||
MediaDecoderReaderInit init(this);
|
||||
init.mVideoFrameContainer = GetVideoFrameContainer();
|
||||
mReader = new MediaFormatReader(init, mDemuxer);
|
||||
return new MediaDecoderStateMachine(this, mReader);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,8 @@ MP3Decoder::Clone(MediaDecoderInit& aInit)
|
|||
|
||||
MediaDecoderStateMachine*
|
||||
MP3Decoder::CreateStateMachine() {
|
||||
mReader = new MediaFormatReader(this, new MP3Demuxer(mResource));
|
||||
MediaDecoderReaderInit init(this);
|
||||
mReader = new MediaFormatReader(init, new MP3Demuxer(mResource));
|
||||
return new MediaDecoderStateMachine(this, mReader);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,9 @@ namespace mozilla {
|
|||
MediaDecoderStateMachine* OggDecoder::CreateStateMachine()
|
||||
{
|
||||
RefPtr<OggDemuxer> demuxer = new OggDemuxer(mResource);
|
||||
mReader = new MediaFormatReader(this, demuxer, GetVideoFrameContainer());
|
||||
MediaDecoderReaderInit init(this);
|
||||
init.mVideoFrameContainer = GetVideoFrameContainer();
|
||||
mReader = new MediaFormatReader(init, demuxer);
|
||||
demuxer->SetChainingEvents(&mReader->TimedMetadataProducer(),
|
||||
&mReader->MediaNotSeekableProducer());
|
||||
return new MediaDecoderStateMachine(this, mReader);
|
||||
|
|
|
@ -22,7 +22,8 @@ WaveDecoder::Clone(MediaDecoderInit& aInit)
|
|||
MediaDecoderStateMachine*
|
||||
WaveDecoder::CreateStateMachine()
|
||||
{
|
||||
mReader = new MediaFormatReader(this, new WAVDemuxer(mResource));
|
||||
MediaDecoderReaderInit init(this);
|
||||
mReader = new MediaFormatReader(init, new WAVDemuxer(mResource));
|
||||
return new MediaDecoderStateMachine(this, mReader);
|
||||
}
|
||||
|
||||
|
|
|
@ -193,8 +193,9 @@ MediaDecodeTask::CreateReader()
|
|||
// If you change this list to add support for new decoders, please consider
|
||||
// updating HTMLMediaElement::CreateDecoder as well.
|
||||
|
||||
mDecoderReader =
|
||||
DecoderTraits::CreateReader(mContainerType, mBufferDecoder, resource);
|
||||
MediaDecoderReaderInit init(mBufferDecoder);
|
||||
init.mResource = resource;
|
||||
mDecoderReader = DecoderTraits::CreateReader(mContainerType, init);
|
||||
|
||||
if (!mDecoderReader) {
|
||||
return false;
|
||||
|
|
|
@ -18,8 +18,9 @@ namespace mozilla {
|
|||
|
||||
MediaDecoderStateMachine* WebMDecoder::CreateStateMachine()
|
||||
{
|
||||
mReader = new MediaFormatReader(
|
||||
this, new WebMDemuxer(mResource), GetVideoFrameContainer());
|
||||
MediaDecoderReaderInit init(this);
|
||||
init.mVideoFrameContainer = GetVideoFrameContainer();
|
||||
mReader = new MediaFormatReader(init, new WebMDemuxer(mResource));
|
||||
return new MediaDecoderStateMachine(this, mReader);
|
||||
}
|
||||
|
||||
|
|
|
@ -2881,11 +2881,7 @@ ScriptLoader::PrepareLoadedRequest(ScriptLoadRequest* aRequest,
|
|||
}
|
||||
|
||||
nsAutoCString sourceMapURL;
|
||||
rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("SourceMap"), sourceMapURL);
|
||||
if (NS_FAILED(rv)) {
|
||||
rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("X-SourceMap"), sourceMapURL);
|
||||
}
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (nsContentUtils::GetSourceMapURL(httpChannel, sourceMapURL)) {
|
||||
aRequest->mHasSourceMapURL = true;
|
||||
aRequest->mSourceMapURL = NS_ConvertUTF8toUTF16(sourceMapURL);
|
||||
}
|
||||
|
|
|
@ -24,4 +24,11 @@ interface StyleSheet {
|
|||
readonly attribute MediaList media;
|
||||
[Pure]
|
||||
attribute boolean disabled;
|
||||
// If a SourceMap or X-SourceMap response header is seen, this is
|
||||
// the value. If both are seen, SourceMap is preferred. If neither
|
||||
// is seen, this will be an empty string. Because this relies on
|
||||
// the HTTP response, it can change if checked before the response
|
||||
// is available -- which is why it is not [Constant].
|
||||
[ChromeOnly, Pure]
|
||||
readonly attribute DOMString sourceMapURL;
|
||||
};
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* global processLDAPValues */
|
||||
/* -*- tab-width: 4; indent-tabs-mode: nil; js-indent-level: 4 -*-
|
||||
* 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
|
||||
|
@ -14,15 +15,15 @@ var gVersion;
|
|||
var gIsUTF8;
|
||||
|
||||
function getPrefBranch() {
|
||||
|
||||
|
||||
var prefService = Components.classes[PrefServiceContractID]
|
||||
.getService(nsIPrefService);
|
||||
.getService(nsIPrefService);
|
||||
return prefService.getBranch(null);
|
||||
}
|
||||
|
||||
function pref(prefName, value) {
|
||||
|
||||
try {
|
||||
try {
|
||||
var prefBranch = getPrefBranch();
|
||||
|
||||
if (typeof value == "string") {
|
||||
|
@ -31,24 +32,21 @@ function pref(prefName, value) {
|
|||
return;
|
||||
}
|
||||
prefBranch.setCharPref(prefName, value);
|
||||
}
|
||||
else if (typeof value == "number") {
|
||||
} else if (typeof value == "number") {
|
||||
prefBranch.setIntPref(prefName, value);
|
||||
}
|
||||
else if (typeof value == "boolean") {
|
||||
} else if (typeof value == "boolean") {
|
||||
prefBranch.setBoolPref(prefName, value);
|
||||
}
|
||||
}
|
||||
catch(e) {
|
||||
} catch (e) {
|
||||
displayError("pref", e);
|
||||
}
|
||||
}
|
||||
|
||||
function defaultPref(prefName, value) {
|
||||
|
||||
|
||||
try {
|
||||
var prefService = Components.classes[PrefServiceContractID]
|
||||
.getService(nsIPrefService);
|
||||
.getService(nsIPrefService);
|
||||
var prefBranch = prefService.getDefaultBranch(null);
|
||||
if (typeof value == "string") {
|
||||
if (gIsUTF8) {
|
||||
|
@ -56,32 +54,28 @@ function defaultPref(prefName, value) {
|
|||
return;
|
||||
}
|
||||
prefBranch.setCharPref(prefName, value);
|
||||
}
|
||||
else if (typeof value == "number") {
|
||||
} else if (typeof value == "number") {
|
||||
prefBranch.setIntPref(prefName, value);
|
||||
}
|
||||
else if (typeof value == "boolean") {
|
||||
} else if (typeof value == "boolean") {
|
||||
prefBranch.setBoolPref(prefName, value);
|
||||
}
|
||||
}
|
||||
catch(e) {
|
||||
} catch (e) {
|
||||
displayError("defaultPref", e);
|
||||
}
|
||||
}
|
||||
|
||||
function lockPref(prefName, value) {
|
||||
|
||||
|
||||
try {
|
||||
var prefBranch = getPrefBranch();
|
||||
|
||||
|
||||
if (prefBranch.prefIsLocked(prefName))
|
||||
prefBranch.unlockPref(prefName);
|
||||
|
||||
|
||||
defaultPref(prefName, value);
|
||||
|
||||
|
||||
prefBranch.lockPref(prefName);
|
||||
}
|
||||
catch(e) {
|
||||
} catch (e) {
|
||||
displayError("lockPref", e);
|
||||
}
|
||||
}
|
||||
|
@ -92,37 +86,36 @@ function unlockPref(prefName) {
|
|||
|
||||
var prefBranch = getPrefBranch();
|
||||
prefBranch.unlockPref(prefName);
|
||||
}
|
||||
catch(e) {
|
||||
} catch (e) {
|
||||
displayError("unlockPref", e);
|
||||
}
|
||||
}
|
||||
|
||||
function getPref(prefName) {
|
||||
|
||||
|
||||
try {
|
||||
var prefBranch = getPrefBranch();
|
||||
|
||||
|
||||
switch (prefBranch.getPrefType(prefName)) {
|
||||
|
||||
|
||||
case prefBranch.PREF_STRING:
|
||||
if (gIsUTF8) {
|
||||
return prefBranch.getStringPref(prefName);
|
||||
}
|
||||
return prefBranch.getCharPref(prefName);
|
||||
|
||||
|
||||
case prefBranch.PREF_INT:
|
||||
return prefBranch.getIntPref(prefName);
|
||||
|
||||
|
||||
case prefBranch.PREF_BOOL:
|
||||
return prefBranch.getBoolPref(prefName);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch(e) {
|
||||
} catch (e) {
|
||||
displayError("getPref", e);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function clearPref(prefName) {
|
||||
|
@ -130,10 +123,9 @@ function clearPref(prefName) {
|
|||
try {
|
||||
var prefBranch = getPrefBranch();
|
||||
prefBranch.clearUserPref(prefName);
|
||||
} catch (e) {
|
||||
}
|
||||
catch(e) {
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
function setLDAPVersion(version) {
|
||||
|
@ -142,7 +134,7 @@ function setLDAPVersion(version) {
|
|||
|
||||
|
||||
function getLDAPAttributes(host, base, filter, attribs, isSecure) {
|
||||
|
||||
|
||||
try {
|
||||
var urlSpec = "ldap" + (isSecure ? "s" : "") + "://" + host + (isSecure ? ":636" : "") + "/" + base + "?" + attribs + "?sub?" +
|
||||
filter;
|
||||
|
@ -157,10 +149,9 @@ function getLDAPAttributes(host, base, filter, attribs, isSecure) {
|
|||
// default to LDAP v3
|
||||
if (!gVersion)
|
||||
gVersion = Components.interfaces.nsILDAPConnection.VERSION3
|
||||
// user supplied method
|
||||
// user supplied method
|
||||
processLDAPValues(ldapquery.getQueryResults(url, gVersion));
|
||||
}
|
||||
catch(e) {
|
||||
} catch (e) {
|
||||
displayError("getLDAPAttibutes", e);
|
||||
}
|
||||
}
|
||||
|
@ -170,24 +161,24 @@ function getLDAPValue(str, key) {
|
|||
try {
|
||||
if (str == null || key == null)
|
||||
return null;
|
||||
|
||||
|
||||
var search_key = "\n" + key + "=";
|
||||
|
||||
|
||||
var start_pos = str.indexOf(search_key);
|
||||
if (start_pos == -1)
|
||||
return null;
|
||||
|
||||
|
||||
start_pos += search_key.length;
|
||||
|
||||
|
||||
var end_pos = str.indexOf("\n", start_pos);
|
||||
if (end_pos == -1)
|
||||
end_pos = str.length;
|
||||
|
||||
|
||||
return str.substring(start_pos, end_pos);
|
||||
}
|
||||
catch(e) {
|
||||
} catch (e) {
|
||||
displayError("getLDAPValue", e);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function displayError(funcname, message) {
|
||||
|
@ -202,8 +193,7 @@ function displayError(funcname, message) {
|
|||
var title = bundle.GetStringFromName("autoConfigTitle");
|
||||
var msg = bundle.formatStringFromName("autoConfigMsg", [funcname], 1);
|
||||
promptService.alert(null, title, msg + " " + message);
|
||||
}
|
||||
catch(e) { }
|
||||
} catch (e) { }
|
||||
}
|
||||
|
||||
function getenv(name) {
|
||||
|
@ -211,9 +201,8 @@ function getenv(name) {
|
|||
var environment = Components.classes["@mozilla.org/process/environment;1"].
|
||||
getService(Components.interfaces.nsIEnvironment);
|
||||
return environment.get(name);
|
||||
}
|
||||
catch(e) {
|
||||
} catch (e) {
|
||||
displayError("getEnvironment", e);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"plugin:mozilla/xpcshell-test"
|
||||
]
|
||||
};
|
|
@ -1,3 +1,4 @@
|
|||
/* global pref */
|
||||
pref("general.config.filename", "autoconfig.cfg");
|
||||
pref("general.config.vendor", "autoconfig");
|
||||
pref("general.config.obscure_value", 0);
|
||||
|
|
|
@ -3,14 +3,16 @@
|
|||
|
||||
var {classes: Cc, interfaces: Ci, results: Cr} = Components;
|
||||
|
||||
/* eslint no-unsafe-finally: "off"*/
|
||||
/* Turning off this rule to allow control flow operations in finally block
|
||||
* http://eslint.org/docs/rules/no-unsafe-finally */
|
||||
function run_test() {
|
||||
let dirSvc = Cc["@mozilla.org/file/directory_service;1"].
|
||||
getService(Ci.nsIProperties);
|
||||
let obsvc = Cc['@mozilla.org/observer-service;1'].
|
||||
let obsvc = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
let ps = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefService);
|
||||
let defaultPrefs = ps.getDefaultBranch(null);
|
||||
let prefs = ps.getBranch(null);
|
||||
|
||||
let greD = dirSvc.get("GreD", Ci.nsIFile);
|
||||
|
@ -53,14 +55,14 @@ function run_test() {
|
|||
let autoConfigCfg = testDir.clone();
|
||||
autoConfigCfg.append(test.filename);
|
||||
autoConfigCfg.copyTo(greD, "autoconfig.cfg");
|
||||
|
||||
|
||||
obsvc.notifyObservers(ps, "prefservice:before-read-userprefs");
|
||||
|
||||
|
||||
for (let prefName in test.prefs) {
|
||||
do_check_eq(test.prefs[prefName],
|
||||
prefs.getStringPref(prefName));
|
||||
}
|
||||
|
||||
|
||||
ps.resetPrefs();
|
||||
// Make sure pref values are reset.
|
||||
for (let prefName in test.prefs) {
|
||||
|
@ -94,4 +96,3 @@ function run_test() {
|
|||
ps.resetPrefs();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ class GPUChild;
|
|||
// GPUProcessHosts are allocated and managed by GPUProcessManager. For all
|
||||
// intents and purposes it is a singleton, though more than one may be allocated
|
||||
// at a time due to its shutdown being asynchronous.
|
||||
class GPUProcessHost final : public ipc::GeckoChildProcessHost
|
||||
class GPUProcessHost final : public mozilla::ipc::GeckoChildProcessHost
|
||||
{
|
||||
friend class GPUChild;
|
||||
|
||||
|
@ -121,7 +121,7 @@ private:
|
|||
DISALLOW_COPY_AND_ASSIGN(GPUProcessHost);
|
||||
|
||||
Listener* mListener;
|
||||
ipc::TaskFactory<GPUProcessHost> mTaskFactory;
|
||||
mozilla::ipc::TaskFactory<GPUProcessHost> mTaskFactory;
|
||||
|
||||
enum class LaunchPhase {
|
||||
Unlaunched,
|
||||
|
|
|
@ -99,10 +99,10 @@ public:
|
|||
|
||||
bool CreateContentBridges(
|
||||
base::ProcessId aOtherProcess,
|
||||
ipc::Endpoint<PCompositorManagerChild>* aOutCompositor,
|
||||
ipc::Endpoint<PImageBridgeChild>* aOutImageBridge,
|
||||
ipc::Endpoint<PVRManagerChild>* aOutVRBridge,
|
||||
ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutVideoManager,
|
||||
mozilla::ipc::Endpoint<PCompositorManagerChild>* aOutCompositor,
|
||||
mozilla::ipc::Endpoint<PImageBridgeChild>* aOutImageBridge,
|
||||
mozilla::ipc::Endpoint<PVRManagerChild>* aOutVRBridge,
|
||||
mozilla::ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutVideoManager,
|
||||
nsTArray<uint32_t>* aNamespaces);
|
||||
|
||||
// This returns a reference to the APZCTreeManager to which
|
||||
|
@ -185,13 +185,13 @@ private:
|
|||
void OnXPCOMShutdown();
|
||||
|
||||
bool CreateContentCompositorManager(base::ProcessId aOtherProcess,
|
||||
ipc::Endpoint<PCompositorManagerChild>* aOutEndpoint);
|
||||
mozilla::ipc::Endpoint<PCompositorManagerChild>* aOutEndpoint);
|
||||
bool CreateContentImageBridge(base::ProcessId aOtherProcess,
|
||||
ipc::Endpoint<PImageBridgeChild>* aOutEndpoint);
|
||||
mozilla::ipc::Endpoint<PImageBridgeChild>* aOutEndpoint);
|
||||
bool CreateContentVRManager(base::ProcessId aOtherProcess,
|
||||
ipc::Endpoint<PVRManagerChild>* aOutEndpoint);
|
||||
mozilla::ipc::Endpoint<PVRManagerChild>* aOutEndpoint);
|
||||
void CreateContentVideoDecoderManager(base::ProcessId aOtherProcess,
|
||||
ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutEndPoint);
|
||||
mozilla::ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutEndPoint);
|
||||
|
||||
// Called from RemoteCompositorSession. We track remote sessions so we can
|
||||
// notify their owning widgets that the session must be restarted.
|
||||
|
@ -258,7 +258,7 @@ private:
|
|||
bool mDecodeVideoOnGpuProcess = true;
|
||||
|
||||
RefPtr<Observer> mObserver;
|
||||
ipc::TaskFactory<GPUProcessManager> mTaskFactory;
|
||||
mozilla::ipc::TaskFactory<GPUProcessManager> mTaskFactory;
|
||||
RefPtr<VsyncIOThreadHolder> mVsyncIOThread;
|
||||
uint32_t mNextNamespace;
|
||||
uint32_t mIdNamespace;
|
||||
|
|
|
@ -72,13 +72,6 @@ UTCToLocalStandardOffsetSeconds()
|
|||
using js::SecondsPerHour;
|
||||
using js::SecondsPerMinute;
|
||||
|
||||
#if defined(XP_WIN)
|
||||
// Windows doesn't follow POSIX: updates to the TZ environment variable are
|
||||
// not reflected immediately on that platform as they are on other systems
|
||||
// without this call.
|
||||
_tzset();
|
||||
#endif
|
||||
|
||||
// Get the current time.
|
||||
time_t currentMaybeWithDST = time(nullptr);
|
||||
if (currentMaybeWithDST == time_t(-1))
|
||||
|
@ -180,13 +173,6 @@ js::DateTimeInfo::computeDSTOffsetMilliseconds(int64_t utcSeconds)
|
|||
MOZ_ASSERT(utcSeconds >= 0);
|
||||
MOZ_ASSERT(utcSeconds <= MaxUnixTimeT);
|
||||
|
||||
#if defined(XP_WIN)
|
||||
// Windows does not follow POSIX. Updates to the TZ environment variable
|
||||
// are not reflected immediately on that platform as they are on UNIX
|
||||
// systems without this call.
|
||||
_tzset();
|
||||
#endif
|
||||
|
||||
struct tm tm;
|
||||
if (!ComputeLocalTime(static_cast<time_t>(utcSeconds), &tm))
|
||||
return 0;
|
||||
|
|
|
@ -4278,7 +4278,8 @@ ConnectAnonymousTreeDescendants(nsIContent* aParent,
|
|||
}
|
||||
}
|
||||
|
||||
void SetNativeAnonymousBitOnDescendants(nsIContent *aRoot)
|
||||
static void
|
||||
SetNativeAnonymousBitOnDescendants(nsIContent* aRoot)
|
||||
{
|
||||
for (nsIContent* curr = aRoot; curr; curr = curr->GetNextNode(aRoot)) {
|
||||
curr->SetFlags(NODE_IS_NATIVE_ANONYMOUS);
|
||||
|
@ -5898,7 +5899,7 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState
|
|||
}
|
||||
}
|
||||
|
||||
bool isGeneratedContent = ((aFlags & ITEM_IS_GENERATED_CONTENT) != 0);
|
||||
const bool isGeneratedContent = !!(aFlags & ITEM_IS_GENERATED_CONTENT);
|
||||
|
||||
// Pre-check for display "none" - if we find that, don't create
|
||||
// any frame at all
|
||||
|
@ -7342,7 +7343,8 @@ nsCSSFrameConstructor::CreateNeededFrames(
|
|||
}
|
||||
}
|
||||
|
||||
void nsCSSFrameConstructor::CreateNeededFrames()
|
||||
void
|
||||
nsCSSFrameConstructor::CreateNeededFrames()
|
||||
{
|
||||
NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
|
||||
"Someone forgot a script blocker");
|
||||
|
@ -7352,7 +7354,8 @@ void nsCSSFrameConstructor::CreateNeededFrames()
|
|||
"root element should not have frame created lazily");
|
||||
if (rootElement && rootElement->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
|
||||
BeginUpdate();
|
||||
TreeMatchContext treeMatchContext(mDocument, TreeMatchContext::ForFrameConstruction);
|
||||
TreeMatchContext treeMatchContext(
|
||||
mDocument, TreeMatchContext::ForFrameConstruction);
|
||||
treeMatchContext.InitAncestors(rootElement);
|
||||
CreateNeededFrames(rootElement, treeMatchContext);
|
||||
EndUpdate();
|
||||
|
@ -7949,8 +7952,6 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
|
|||
|
||||
NS_PRECONDITION(aStartChild, "must always pass a child");
|
||||
|
||||
// XXXldb Do we need to re-resolve style to handle the CSS2 + combinator and
|
||||
// the :empty pseudo-class?
|
||||
#ifdef DEBUG
|
||||
if (gNoisyContentUpdates) {
|
||||
printf("nsCSSFrameConstructor::ContentRangeInserted container=%p "
|
||||
|
@ -7966,9 +7967,7 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
for (nsIContent* child = aStartChild;
|
||||
child != aEndChild;
|
||||
child = child->GetNextSibling()) {
|
||||
|
@ -8010,45 +8009,39 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
|
|||
// If we have a null parent, then this must be the document element being
|
||||
// inserted, or some other child of the document in the DOM (might be a PI,
|
||||
// say).
|
||||
if (! aContainer) {
|
||||
if (!aContainer) {
|
||||
NS_ASSERTION(isSingleInsert,
|
||||
"root node insertion should be a single insertion");
|
||||
Element *docElement = mDocument->GetRootElement();
|
||||
Element* docElement = mDocument->GetRootElement();
|
||||
|
||||
if (aStartChild != docElement) {
|
||||
// Not the root element; just bail out
|
||||
return;
|
||||
}
|
||||
|
||||
NS_PRECONDITION(nullptr == mRootElementFrame,
|
||||
"root element frame already created");
|
||||
NS_PRECONDITION(!mRootElementFrame, "root element frame already created");
|
||||
|
||||
// Create frames for the document element and its child elements
|
||||
nsIFrame* docElementFrame =
|
||||
ConstructDocElementFrame(docElement, aFrameState);
|
||||
|
||||
if (docElementFrame) {
|
||||
if (ConstructDocElementFrame(docElement, aFrameState)) {
|
||||
InvalidateCanvasIfNeeded(mPresShell, aStartChild);
|
||||
#ifdef DEBUG
|
||||
if (gReallyNoisyContentUpdates) {
|
||||
printf("nsCSSFrameConstructor::ContentRangeInserted: resulting frame "
|
||||
"model:\n");
|
||||
docElementFrame->List(stdout, 0);
|
||||
mRootElementFrame->List(stdout, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (aFrameState) {
|
||||
// Restore frame state for the root scroll frame if there is one
|
||||
nsIFrame* rootScrollFrame = mPresShell->GetRootScrollFrame();
|
||||
if (rootScrollFrame) {
|
||||
if (nsIFrame* rootScrollFrame = mPresShell->GetRootScrollFrame()) {
|
||||
RestoreFrameStateFor(rootScrollFrame, aFrameState);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
nsAccessibilityService* accService = nsIPresShell::AccService();
|
||||
if (accService) {
|
||||
if (nsAccessibilityService* accService = nsIPresShell::AccService()) {
|
||||
accService->ContentRangeInserted(mPresShell, aContainer,
|
||||
aStartChild, aEndChild);
|
||||
}
|
||||
|
@ -8549,27 +8542,32 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
|
|||
*aDestroyedFramesFor = aChild;
|
||||
}
|
||||
|
||||
// We're destroying our frame(s). This normally happens either when the content
|
||||
// is being removed from the DOM (in which case we'll drop all Servo data in
|
||||
// UnbindFromTree), or when we're recreating frames (usually in response to
|
||||
// having retrieved a ReconstructFrame change hint after restyling). In both of
|
||||
// those cases, there are no pending restyles we need to worry about.
|
||||
// We're destroying our frame(s). This normally happens either when the
|
||||
// content is being removed from the DOM (in which case we'll drop all Servo
|
||||
// data in UnbindFromTree), or when we're recreating frames (usually in
|
||||
// response to having retrieved a ReconstructFrame change hint after
|
||||
// restyling). In both of those cases, there are no pending restyles we need
|
||||
// to worry about.
|
||||
//
|
||||
// However, there is also the (rare) DestroyFramesFor path, in which we tear
|
||||
// down (and usually recreate) the frames for a subtree. In this case, leaving
|
||||
// the style data on the elements is problematic for our invariants, because
|
||||
// there might be pending restyles in the subtree. If we simply leave them as-is,
|
||||
// the subsequent traversal when recreating frames will generate a bunch of bogus
|
||||
// change hints to update frames that no longer exist.
|
||||
// there might be pending restyles in the subtree. If we simply leave them
|
||||
// as-is, the subsequent traversal when recreating frames will generate a
|
||||
// bunch of bogus change hints to update frames that no longer exist.
|
||||
//
|
||||
// So the two obvious options are to (1) process all pending restyles and take all
|
||||
// the change hints before destroying the frames, or (2) drop all the style data.
|
||||
// We chose the latter, since that matches the performance characteristics of the
|
||||
// old Gecko style system.
|
||||
// So the two obvious options are to (1) process all pending restyles and take
|
||||
// all the change hints before destroying the frames, or (2) drop all the
|
||||
// style data. We chose the latter, since that matches the performance
|
||||
// characteristics of the old Gecko style system.
|
||||
//
|
||||
// That said, it's almost certainly possible to optimize this if it turns out to be
|
||||
// hot. It's just not a priority at the moment.
|
||||
if (aFlags == REMOVE_DESTROY_FRAMES && aChild->IsElement() && aChild->IsStyledByServo()) {
|
||||
// That said, it's almost certainly possible to optimize this if it turns out
|
||||
// to be hot. It's just not a priority at the moment.
|
||||
//
|
||||
// FIXME(emilio): This really really feels like a hack, and it's only for the
|
||||
// XBL/Shadow DOM path, so we should do this there instead.
|
||||
if (aFlags == REMOVE_DESTROY_FRAMES && aChild->IsElement() &&
|
||||
aChild->IsStyledByServo()) {
|
||||
ServoRestyleManager::ClearServoDataFromSubtree(aChild->AsElement());
|
||||
}
|
||||
|
||||
|
@ -8588,9 +8586,6 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
|
|||
presContext->UpdateViewportScrollbarStylesOverride();
|
||||
}
|
||||
|
||||
// XXXldb Do we need to re-resolve style to handle the CSS2 + combinator and
|
||||
// the :empty pseudo-class?
|
||||
|
||||
#ifdef DEBUG
|
||||
if (gNoisyContentUpdates) {
|
||||
printf("nsCSSFrameConstructor::ContentRemoved container=%p child=%p "
|
||||
|
@ -8655,7 +8650,6 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
|
|||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#endif // MOZ_XUL
|
||||
|
||||
// If we're removing the root, then make sure to remove things starting at
|
||||
|
@ -8684,10 +8678,10 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
|
|||
if (aContainer && aContainer->HasFlag(NODE_IS_IN_SHADOW_TREE) &&
|
||||
!aContainer->IsInNativeAnonymousSubtree() &&
|
||||
!aChild->IsInNativeAnonymousSubtree()) {
|
||||
// Recreate frames if content is removed from a ShadowRoot
|
||||
// because it may contain an insertion point which can change
|
||||
// how the host is rendered.
|
||||
//XXXsmaug This is super unefficient!
|
||||
// Recreate frames if content is removed from a ShadowRoot because it may
|
||||
// contain an insertion point which can change how the host is rendered.
|
||||
//
|
||||
// XXXsmaug This is super unefficient!
|
||||
nsIContent* bindingParent = aContainer->GetBindingParent();
|
||||
*aDidReconstruct = true;
|
||||
LAYOUT_PHASE_TEMP_EXIT();
|
||||
|
@ -9102,23 +9096,28 @@ nsCSSFrameConstructor::WillDestroyFrameTree()
|
|||
|
||||
// XXXbz I'd really like this method to go away. Once we have inline-block and
|
||||
// I can just use that for sized broken images, that can happen, maybe.
|
||||
void nsCSSFrameConstructor::GetAlternateTextFor(nsIContent* aContent,
|
||||
nsIAtom* aTag, // content object's tag
|
||||
nsXPIDLString& aAltText)
|
||||
void
|
||||
nsCSSFrameConstructor::GetAlternateTextFor(nsIContent* aContent,
|
||||
nsIAtom* aTag,
|
||||
nsXPIDLString& aAltText)
|
||||
{
|
||||
// The "alt" attribute specifies alternate text that is rendered
|
||||
// when the image can not be displayed
|
||||
// when the image can not be displayed.
|
||||
if (aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aAltText)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If there's no "alt" attribute, and aContent is an input
|
||||
// element, then use the value of the "value" attribute
|
||||
if (!aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aAltText) &&
|
||||
nsGkAtoms::input == aTag) {
|
||||
// If there's no "value" attribute either, then use the localized string
|
||||
// for "Submit" as the alternate text.
|
||||
if (!aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aAltText)) {
|
||||
nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
|
||||
"Submit", aAltText);
|
||||
if (nsGkAtoms::input == aTag) {
|
||||
// If there's no "alt" attribute, and aContent is an input element, then use
|
||||
// the value of the "value" attribute
|
||||
if (aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aAltText)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If there's no "value" attribute either, then use the localized string for
|
||||
// "Submit" as the alternate text.
|
||||
nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
|
||||
"Submit", aAltText);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10854,7 +10853,8 @@ nsCSSFrameConstructor::WrapItemsInPseudoParent(nsIContent* aParentContent,
|
|||
aIter.InsertItem(newItem);
|
||||
}
|
||||
|
||||
void nsCSSFrameConstructor::CreateNeededPseudoSiblings(
|
||||
void
|
||||
nsCSSFrameConstructor::CreateNeededPseudoSiblings(
|
||||
nsFrameConstructorState& aState,
|
||||
FrameConstructionItemList& aItems,
|
||||
nsIFrame* aParentFrame)
|
||||
|
|
|
@ -60,7 +60,7 @@ public:
|
|||
friend class mozilla::ServoRestyleManager;
|
||||
|
||||
nsCSSFrameConstructor(nsIDocument* aDocument, nsIPresShell* aPresShell);
|
||||
~nsCSSFrameConstructor(void) {
|
||||
~nsCSSFrameConstructor() {
|
||||
MOZ_ASSERT(mUpdateCount == 0, "Dying in the middle of our own update?");
|
||||
}
|
||||
|
||||
|
|
|
@ -891,6 +891,11 @@ SheetLoadData::OnStreamComplete(nsIUnicharStreamLoader* aLoader,
|
|||
mLoader->SheetComplete(this, NS_ERROR_NOT_AVAILABLE);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoCString sourceMapURL;
|
||||
if (nsContentUtils::GetSourceMapURL(httpChannel, sourceMapURL)) {
|
||||
mSheet->SetSourceMapURL(NS_ConvertUTF8toUTF16(sourceMapURL));
|
||||
}
|
||||
}
|
||||
|
||||
nsAutoCString contentType;
|
||||
|
|
|
@ -259,6 +259,7 @@ StyleSheetInfo::StyleSheetInfo(StyleSheetInfo& aCopy,
|
|||
, mComplete(aCopy.mComplete)
|
||||
, mFirstChild() // We don't rebuild the child because we're making a copy
|
||||
// without children.
|
||||
, mSourceMapURL(aCopy.mSourceMapURL)
|
||||
#ifdef DEBUG
|
||||
, mPrincipalSet(aCopy.mPrincipalSet)
|
||||
#endif
|
||||
|
@ -506,6 +507,18 @@ StyleSheet::GetCssRules(nsIPrincipal& aSubjectPrincipal,
|
|||
FORWARD_INTERNAL(GetCssRulesInternal, ())
|
||||
}
|
||||
|
||||
void
|
||||
StyleSheet::GetSourceMapURL(nsAString& aSourceMapURL)
|
||||
{
|
||||
aSourceMapURL = mInner->mSourceMapURL;
|
||||
}
|
||||
|
||||
void
|
||||
StyleSheet::SetSourceMapURL(const nsAString& aSourceMapURL)
|
||||
{
|
||||
mInner->mSourceMapURL = aSourceMapURL;
|
||||
}
|
||||
|
||||
css::Rule*
|
||||
StyleSheet::GetDOMOwnerRule() const
|
||||
{
|
||||
|
|
|
@ -213,6 +213,8 @@ public:
|
|||
dom::MediaList* Media();
|
||||
bool Disabled() const { return mDisabled; }
|
||||
// The XPCOM SetDisabled is fine for WebIDL.
|
||||
void GetSourceMapURL(nsAString& aTitle);
|
||||
void SetSourceMapURL(const nsAString& aSourceMapURL);
|
||||
|
||||
// WebIDL CSSStyleSheet API
|
||||
// Can't be inline because we can't include ImportRule here. And can't be
|
||||
|
|
|
@ -61,6 +61,11 @@ struct StyleSheetInfo
|
|||
RefPtr<StyleSheet> mFirstChild;
|
||||
AutoTArray<StyleSheet*, 8> mSheets;
|
||||
|
||||
// If a SourceMap or X-SourceMap response header is seen, this is
|
||||
// the value. If both are seen, SourceMap is preferred. If neither
|
||||
// is seen, this will be an empty string.
|
||||
nsString mSourceMapURL;
|
||||
|
||||
#ifdef DEBUG
|
||||
bool mPrincipalSet;
|
||||
#endif
|
||||
|
|
|
@ -3,6 +3,12 @@ support-files =
|
|||
bug453896_iframe.html
|
||||
media_queries_iframe.html
|
||||
newtab_share_rule_processors.html
|
||||
mapped.css
|
||||
mapped.css^headers^
|
||||
mapped2.css
|
||||
mapped2.css^headers^
|
||||
sourcemap_css.html
|
||||
|
||||
[browser_bug453896.js]
|
||||
[browser_newtab_share_rule_processors.js]
|
||||
[browser_sourcemap.js]
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
add_task(async function() {
|
||||
let uri = "http://example.com/browser/layout/style/test/sourcemap_css.html";
|
||||
info(`URI is ${uri}`);
|
||||
|
||||
await BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: uri
|
||||
}, async function(browser) {
|
||||
await ContentTask.spawn(browser, null, function* () {
|
||||
let seenSheets = 0;
|
||||
|
||||
for (let i = 0; i < content.document.styleSheets.length; ++i) {
|
||||
let sheet = content.document.styleSheets[i];
|
||||
|
||||
info(`Checking ${sheet.href}`);
|
||||
if (/mapped\.css/.test(sheet.href)) {
|
||||
is(sheet.sourceMapURL, "mapped.css.map", "X-SourceMap header took effect");
|
||||
seenSheets |= 1;
|
||||
} else if (/mapped2\.css/.test(sheet.href)) {
|
||||
is(sheet.sourceMapURL, "mapped2.css.map", "SourceMap header took effect");
|
||||
seenSheets |= 2;
|
||||
} else {
|
||||
ok(false, "sheet does not have source map URL");
|
||||
}
|
||||
}
|
||||
|
||||
is(seenSheets, 3, "seen all source-mapped sheets");
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,3 @@
|
|||
div {
|
||||
color: #f06;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
X-SourceMap: mapped.css.map
|
|
@ -0,0 +1,3 @@
|
|||
span {
|
||||
color: #f06;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
SourceMap: mapped2.css.map
|
||||
X-SourceMap: ignored.css.map
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for bug 1306887</title>
|
||||
<link rel="stylesheet" type="text/css" href="mapped.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="mapped2.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1306887">Mozilla Bug 1306887</a>
|
||||
</body>
|
||||
</html>
|
|
@ -49,7 +49,7 @@ to mochitest command.
|
|||
* test_grid_container_shorthands.html [65]
|
||||
* test_grid_item_shorthands.html [23]
|
||||
* test_grid_shorthand_serialization.html [28]
|
||||
* test_value_storage.html `'grid` [41]
|
||||
* test_value_storage.html `'grid` [21]
|
||||
* Unsupported values
|
||||
* SVG-in-OpenType values not supported servo/servo#15211 bug 1355412
|
||||
* test_value_storage.html `context-` [7]
|
||||
|
|
|
@ -830,7 +830,8 @@ MP4MetadataRust::GetNumberTracks(mozilla::TrackInfo::TrackType aType) const
|
|||
continue;
|
||||
}
|
||||
// JPEG 'video' decoder is not supported in media stack yet.
|
||||
if (track_info.codec == mp4parse_codec::mp4parse_codec_JPEG) {
|
||||
if (track_info.codec == mp4parse_codec::mp4parse_codec_JPEG ||
|
||||
track_info.codec == mp4parse_codec::mp4parse_codec_UNKNOWN) {
|
||||
continue;
|
||||
}
|
||||
if (TrackTypeEqual(aType, track_info.track_type)) {
|
||||
|
|
|
@ -1675,7 +1675,10 @@ fn read_video_sample_entry<T: Read>(src: &mut BMFFBox<T>) -> Result<(CodecType,
|
|||
BoxType::VP9SampleEntry => CodecType::VP9,
|
||||
BoxType::ProtectedVisualSampleEntry => CodecType::EncryptedVideo,
|
||||
BoxType::JPEGAtom => CodecType::JPEG,
|
||||
_ => CodecType::Unknown,
|
||||
_ => {
|
||||
log!("Unsupported video codec, box {:?} found", name);
|
||||
CodecType::Unknown
|
||||
}
|
||||
};
|
||||
|
||||
// Skip uninteresting fields.
|
||||
|
@ -1747,20 +1750,23 @@ fn read_video_sample_entry<T: Read>(src: &mut BMFFBox<T>) -> Result<(CodecType,
|
|||
log!("{:?} (sinf)", sinf);
|
||||
protection_info.push(sinf);
|
||||
}
|
||||
_ => skip_box_content(&mut b)?,
|
||||
_ => {
|
||||
log!("Unsupported video codec, box {:?} found", b.head.name);
|
||||
skip_box_content(&mut b)?;
|
||||
}
|
||||
}
|
||||
check_parser_state!(b.content);
|
||||
}
|
||||
|
||||
codec_specific
|
||||
.map(|codec_specific| (codec_type, SampleEntry::Video(VideoSampleEntry {
|
||||
Ok(codec_specific.map_or((CodecType::Unknown, SampleEntry::Unknown),
|
||||
|codec_specific| (codec_type, SampleEntry::Video(VideoSampleEntry {
|
||||
data_reference_index: data_reference_index,
|
||||
width: width,
|
||||
height: height,
|
||||
codec_specific: codec_specific,
|
||||
protection_info: protection_info,
|
||||
})))
|
||||
.ok_or_else(|| Error::InvalidData("malformed video sample entry"))
|
||||
)
|
||||
}
|
||||
|
||||
fn read_qt_wave_atom<T: Read>(src: &mut BMFFBox<T>) -> Result<ES_Descriptor> {
|
||||
|
@ -1889,13 +1895,16 @@ fn read_audio_sample_entry<T: Read>(src: &mut BMFFBox<T>) -> Result<(CodecType,
|
|||
codec_type = CodecType::EC3;
|
||||
codec_specific = Some(AudioCodecSpecific::EC3SpecificBox);
|
||||
}
|
||||
_ => skip_box_content(&mut b)?,
|
||||
_ => {
|
||||
log!("Unsupported audio codec, box {:?} found", b.head.name);
|
||||
skip_box_content(&mut b)?;
|
||||
}
|
||||
}
|
||||
check_parser_state!(b.content);
|
||||
}
|
||||
|
||||
codec_specific
|
||||
.map(|codec_specific| (codec_type, SampleEntry::Audio(AudioSampleEntry {
|
||||
Ok(codec_specific.map_or((CodecType::Unknown, SampleEntry::Unknown),
|
||||
|codec_specific| (codec_type, SampleEntry::Audio(AudioSampleEntry {
|
||||
data_reference_index: data_reference_index,
|
||||
channelcount: channelcount,
|
||||
samplesize: samplesize,
|
||||
|
@ -1903,7 +1912,7 @@ fn read_audio_sample_entry<T: Read>(src: &mut BMFFBox<T>) -> Result<(CodecType,
|
|||
codec_specific: codec_specific,
|
||||
protection_info: protection_info,
|
||||
})))
|
||||
.ok_or_else(|| Error::InvalidData("malformed audio sample entry"))
|
||||
)
|
||||
}
|
||||
|
||||
/// Parse a stsd box.
|
||||
|
|
|
@ -1071,3 +1071,52 @@ fn jpeg_video_sample_entry() {
|
|||
_ => panic!("failed to parse a jpeg atom"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unknown_video_sample_entry() {
|
||||
let unknown_codec = make_box(BoxSize::Auto, b"yyyy", |s| {
|
||||
s.append_repeated(0, 16)
|
||||
}).into_inner();
|
||||
let mut stream = make_box(BoxSize::Auto, b"xxxx", |s| {
|
||||
s.append_repeated(0, 6)
|
||||
.B16(1)
|
||||
.append_repeated(0, 16)
|
||||
.B16(0)
|
||||
.B16(0)
|
||||
.append_repeated(0, 14)
|
||||
.append_repeated(0, 32)
|
||||
.append_repeated(0, 4)
|
||||
.append_bytes(unknown_codec.as_slice())
|
||||
});
|
||||
let mut iter = super::BoxIter::new(&mut stream);
|
||||
let mut stream = iter.next_box().unwrap().unwrap();
|
||||
match super::read_video_sample_entry(&mut stream) {
|
||||
Ok((super::CodecType::Unknown, super::SampleEntry::Unknown)) => (),
|
||||
_ => panic!("expected a different error result"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unknown_audio_sample_entry() {
|
||||
let unknown_codec = make_box(BoxSize::Auto, b"yyyy", |s| {
|
||||
s.append_repeated(0, 16)
|
||||
}).into_inner();
|
||||
let mut stream = make_box(BoxSize::Auto, b"xxxx", |s| {
|
||||
s.append_repeated(0, 6)
|
||||
.B16(1)
|
||||
.B32(0)
|
||||
.B32(0)
|
||||
.B16(2)
|
||||
.B16(16)
|
||||
.B16(0)
|
||||
.B16(0)
|
||||
.B32(48000 << 16)
|
||||
.append_bytes(unknown_codec.as_slice())
|
||||
});
|
||||
let mut iter = super::BoxIter::new(&mut stream);
|
||||
let mut stream = iter.next_box().unwrap().unwrap();
|
||||
match super::read_audio_sample_entry(&mut stream) {
|
||||
Ok((super::CodecType::Unknown, super::SampleEntry::Unknown)) => (),
|
||||
_ => panic!("expected a different error result"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# Script to update mp4parse-rust sources to latest upstream
|
||||
|
||||
# Default version.
|
||||
VER=ae58bb5063cde8018d51c1778a52392777ddb0d4
|
||||
VER=ce7e2e66613009d56aea2588c4d11a23d4dd8056
|
||||
|
||||
# Accept version or commit from the command line.
|
||||
if test -n "$1"; then
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче