Merge autoland to central, a=merge

This commit is contained in:
Wes Kocher 2016-11-08 13:34:10 -08:00
Родитель abf500eeaf 9950817294
Коммит b0767bc340
185 изменённых файлов: 2709 добавлений и 2040 удалений

Просмотреть файл

@ -4,4 +4,12 @@ module.exports = {
"extends": [
"../toolkit/.eslintrc.js"
],
"rules": {
"no-unused-vars": ["error", {
"vars": "local",
"varsIgnorePattern": "^Cc|Ci|Cu|Cr|EXPORTED_SYMBOLS",
"args": "none",
}]
}
};

Просмотреть файл

@ -1,67 +1,69 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
var testData = [
/* baseURI, field name, expected */
[ 'http://example.com/', 'q', 'http://example.com/?q=%s' ],
[ 'http://example.com/new-path-here/', 'q', 'http://example.com/new-path-here/?q=%s' ],
[ '', 'q', 'http://example.org/browser/browser/base/content/test/general/dummy_page.html?q=%s' ],
// Tests for proper behaviour when called on a form whose action contains a question mark.
[ 'http://example.com/search?oe=utf-8', 'q', 'http://example.com/search?oe=utf-8&q=%s' ],
{ desc: "No path",
action: "http://example.com/",
param: "q",
},
{ desc: "With path",
action: "http://example.com/new-path-here/",
param: "q",
},
{ desc: "No action",
action: "",
param: "q",
},
{ desc: "With Query String",
action: "http://example.com/search?oe=utf-8",
param: "q",
},
];
add_task(function*() {
yield BrowserTestUtils.withNewTab({
gBrowser,
url: "http://example.org/browser/browser/base/content/test/general/dummy_page.html",
}, function* (browser) {
yield ContentTask.spawn(browser, null, function* () {
let doc = content.document;
let base = doc.createElement("base");
doc.head.appendChild(base);
});
const TEST_URL = "http://example.org/browser/browser/base/content/test/general/dummy_page.html";
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
var mm = browser.messageManager;
let count = 0;
for (let method of ["GET", "POST"]) {
for (let {desc, action, param } of testData) {
info(`Running ${method} keyword test '${desc}'`);
let id = `keyword-form-${count++}`;
let contextMenu = document.getElementById("contentAreaContextMenu");
let contextMenuPromise =
BrowserTestUtils.waitForEvent(contextMenu, "popupshown")
.then(() => gContextMenuContentData.popupNode);
for (let [baseURI, fieldName, expected] of testData) {
let popupShownPromise = BrowserTestUtils.waitForEvent(document.getElementById("contentAreaContextMenu"),
"popupshown");
yield ContentTask.spawn(browser, { baseURI, fieldName }, function* (args) {
yield ContentTask.spawn(tab.linkedBrowser,
{ action, param, method, id }, function* (args) {
let doc = content.document;
let base = doc.querySelector('head > base');
base.href = args.baseURI;
let form = doc.createElement("form");
form.id = "keyword-form";
form.id = args.id;
form.method = args.method;
form.action = args.action;
let element = doc.createElement("input");
element.setAttribute("type", "text");
element.setAttribute("name", args.fieldName);
element.setAttribute("name", args.param);
form.appendChild(element);
doc.body.appendChild(form);
/* Open context menu so chrome can access the element */
const domWindowUtils =
content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils);
let rect = element.getBoundingClientRect();
let left = rect.left + rect.width / 2;
let top = rect.top + rect.height / 2;
domWindowUtils.sendMouseEvent("contextmenu", left, top, 2,
1, 0, false, 0, 0, true);
});
yield popupShownPromise;
yield BrowserTestUtils.synthesizeMouseAtCenter(`#${id} > input`,
{ type : "contextmenu", button : 2 },
tab.linkedBrowser);
let target = yield contextMenuPromise;
let target = gContextMenuContentData.popupNode;
let urlCheck = new Promise((resolve, reject) => {
yield new Promise(resolve => {
let url = action || tab.linkedBrowser.currentURI.spec;
let mm = tab.linkedBrowser.messageManager;
let onMessage = (message) => {
mm.removeMessageListener("ContextMenu:SearchFieldBookmarkData:Result", onMessage);
is(message.data.spec, expected,
`Bookmark spec for search field named ${fieldName} and baseURI ${baseURI} incorrect`);
if (method == "GET") {
ok(message.data.spec.endsWith(`${param}=%s`),
`Check expected url for field named ${param} and action ${action}`);
} else {
is(message.data.spec, url,
`Check expected url for field named ${param} and action ${action}`);
is(message.data.postData, `${param}%3D%25s`,
`Check expected POST data for field named ${param} and action ${action}`);
}
resolve();
};
mm.addMessageListener("ContextMenu:SearchFieldBookmarkData:Result", onMessage);
@ -69,14 +71,11 @@ add_task(function*() {
mm.sendAsyncMessage("ContextMenu:SearchFieldBookmarkData", null, { target });
});
yield urlCheck;
document.getElementById("contentAreaContextMenu").hidePopup();
yield ContentTask.spawn(browser, null, function* () {
let doc = content.document;
doc.body.removeChild(doc.getElementById("keyword-form"));
});
let popupHiddenPromise = BrowserTestUtils.waitForEvent(contextMenu, "popuphidden");
contextMenu.hidePopup();
yield popupHiddenPromise;
}
});
}
yield BrowserTestUtils.removeTab(tab);
});

Просмотреть файл

@ -7,6 +7,8 @@ support-files =
skip-if = (os == "linux" || os == "mac") && debug # bug 970052, bug 970053
[browser_action_keyword.js]
skip-if = os == "linux" # Bug 1188154
support-files =
print_postdata.sjs
[browser_action_keyword_override.js]
[browser_action_searchengine.js]
[browser_action_searchengine_alias.js]

Просмотреть файл

@ -1,8 +1,3 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
var gOnSearchComplete = null;
function* promise_first_result(inputText) {
yield promiseAutocompleteResultPopup(inputText);
@ -10,41 +5,47 @@ function* promise_first_result(inputText) {
return firstResult;
}
const TEST_URL = "http://mochi.test:8888/browser/browser/base/content/test/urlbar/print_postdata.sjs";
add_task(function*() {
let tab = gBrowser.selectedTab = gBrowser.addTab("about:mozilla");
let tabs = [tab];
add_task(function* setup() {
yield PlacesUtils.keywords.insert({ keyword: "get",
url: TEST_URL + "?q=%s" });
yield PlacesUtils.keywords.insert({ keyword: "post",
url: TEST_URL,
postData: "q=%s" });
registerCleanupFunction(function* () {
for (let tab of tabs)
gBrowser.removeTab(tab);
yield PlacesUtils.bookmarks.remove(bm);
yield PlacesUtils.keywords.remove("get");
yield PlacesUtils.keywords.remove("post");
while (gBrowser.tabs.length > 1) {
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
}
});
});
yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
add_task(function* get_keyword() {
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:mozilla");
let bm = yield PlacesUtils.bookmarks.insert({ parentGuid: PlacesUtils.bookmarks.unfiledGuid,
url: "http://example.com/?q=%s",
title: "test" });
yield PlacesUtils.keywords.insert({ keyword: "keyword",
url: "http://example.com/?q=%s" });
let result = yield promise_first_result("keyword something");
let result = yield promise_first_result("get something");
isnot(result, null, "Expect a keyword result");
let types = new Set(result.getAttribute("type").split(/\s+/));
Assert.ok(types.has("keyword"));
is(result.getAttribute("actiontype"), "keyword", "Expect correct `actiontype` attribute");
is(result.getAttribute("title"), "example.com", "Expect correct title");
is(result.getAttribute("title"), "mochi.test:8888", "Expect correct title");
// We need to make a real URI out of this to ensure it's normalised for
// comparison.
let uri = NetUtil.newURI(result.getAttribute("url"));
is(uri.spec, PlacesUtils.mozActionURI("keyword", {url: "http://example.com/?q=something", input: "keyword something"}), "Expect correct url");
is(uri.spec, PlacesUtils.mozActionURI("keyword",
{ url: TEST_URL + "?q=something",
input: "get something"}),
"Expect correct url");
let titleHbox = result._titleText.parentNode.parentNode;
ok(titleHbox.classList.contains("ac-title"), "Title hbox element sanity check");
is_element_visible(titleHbox, "Title element should be visible");
is(result._titleText.textContent, "example.com: something", "Node should contain the name of the bookmark and query");
is(result._titleText.textContent, "mochi.test:8888: something",
"Node should contain the name of the bookmark and query");
let urlHbox = result._urlText.parentNode.parentNode;
ok(urlHbox.classList.contains("ac-url"), "URL hbox element sanity check");
@ -60,22 +61,59 @@ add_task(function*() {
let tabPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
EventUtils.synthesizeMouseAtCenter(result, {});
yield tabPromise;
is(tab.linkedBrowser.currentURI.spec, "http://example.com/?q=something", "Tab should have loaded from clicking on result");
is(tab.linkedBrowser.currentURI.spec, TEST_URL + "?q=something",
"Tab should have loaded from clicking on result");
// Middle-click on the result
info("Middle-click on result");
result = yield promise_first_result("keyword somethingmore");
result = yield promise_first_result("get somethingmore");
isnot(result, null, "Expect a keyword result");
// We need to make a real URI out of this to ensure it's normalised for
// comparison.
uri = NetUtil.newURI(result.getAttribute("url"));
is(uri.spec, PlacesUtils.mozActionURI("keyword", {url: "http://example.com/?q=somethingmore", input: "keyword somethingmore"}), "Expect correct url");
is(uri.spec, PlacesUtils.mozActionURI("keyword",
{ url: TEST_URL + "?q=somethingmore",
input: "get somethingmore" }),
"Expect correct url");
tabPromise = BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "TabOpen");
EventUtils.synthesizeMouseAtCenter(result, {button: 1});
let tabOpenEvent = yield tabPromise;
let newTab = tabOpenEvent.target;
tabs.push(newTab);
yield BrowserTestUtils.browserLoaded(newTab.linkedBrowser);
is(newTab.linkedBrowser.currentURI.spec, "http://example.com/?q=somethingmore", "Tab should have loaded from middle-clicking on result");
is(newTab.linkedBrowser.currentURI.spec,
TEST_URL + "?q=somethingmore",
"Tab should have loaded from middle-clicking on result");
});
add_task(function* post_keyword() {
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:mozilla");
let result = yield promise_first_result("post something");
isnot(result, null, "Expect a keyword result");
let types = new Set(result.getAttribute("type").split(/\s+/));
Assert.ok(types.has("keyword"));
is(result.getAttribute("actiontype"), "keyword", "Expect correct `actiontype` attribute");
is(result.getAttribute("title"), "mochi.test:8888", "Expect correct title");
is(result.getAttribute("url"),
PlacesUtils.mozActionURI("keyword", { url: TEST_URL,
input: "post something",
"postData": "q=something" }),
"Expect correct url");
// Click on the result
info("Normal click on result");
let tabPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
EventUtils.synthesizeMouseAtCenter(result, {});
yield tabPromise;
is(tab.linkedBrowser.currentURI.spec, TEST_URL,
"Tab should have loaded from clicking on result");
let postData = yield ContentTask.spawn(tab.linkedBrowser, null, function* () {
return content.document.body.textContent;
});
is(postData, "q=something", "post data was submitted correctly");
});

Просмотреть файл

@ -0,0 +1,22 @@
const CC = Components.Constructor;
const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
"nsIBinaryInputStream",
"setInputStream");
function handleRequest(request, response) {
response.setHeader("Content-Type", "text/plain", false);
if (request.method == "GET") {
response.write(request.queryString);
} else {
var body = new BinaryInputStream(request.bodyInputStream);
var avail;
var bytes = [];
while ((avail = body.available()) > 0)
Array.prototype.push.apply(bytes, body.readByteArray(avail));
var data = String.fromCharCode.apply(null, bytes);
response.bodyOutputStream.write(data, data.length);
}
}

Просмотреть файл

@ -444,7 +444,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
break;
case "keyword":
if (action.params.postData) {
postData = getPostDataStream(postData);
postData = getPostDataStream(action.params.postData);
}
mayInheritPrincipal = true;
url = action.params.url;

Просмотреть файл

@ -373,7 +373,7 @@ function openLinkIn(url, where, params) {
}
if (aForceAboutBlankViewerInCurrent) {
w.gBrowser.selectedBrowser.createAboutBlankContentViewer(aPrincipal);
aCurrentBrowser.createAboutBlankContentViewer(aPrincipal);
}
aCurrentBrowser.loadURIWithFlags(url, {

Просмотреть файл

@ -471,9 +471,6 @@ extensions.registerSchemaAPI("browserAction", "addon_parent", context => {
setIcon: function(details) {
let tab = details.tabId !== null ? TabManager.getTab(details.tabId, context) : null;
// Note: the caller in the child process has already normalized
// `details` to not contain an `imageData` property, so the icon can
// safely be normalized here without errors.
let icon = IconDetails.normalize(details, extension, context);
BrowserAction.for(extension).setProperty(tab, "icon", icon);
},

Просмотреть файл

@ -1,26 +0,0 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
var {
IconDetails,
} = ExtensionUtils;
extensions.registerSchemaAPI("browserAction", "addon_child", context => {
return {
browserAction: {
setIcon: function(details) {
// This needs to run in the addon process because normalization requires
// the use of <canvas>.
let normalizedDetails = {
tabId: details.tabId,
path: IconDetails.normalize(details, context.extension, context),
};
return context.childManager.callParentAsyncFunction("browserAction.setIcon", [
normalizedDetails,
]);
},
},
};
});

Просмотреть файл

@ -1,26 +0,0 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
var {
IconDetails,
} = ExtensionUtils;
extensions.registerSchemaAPI("pageAction", "addon_child", context => {
return {
pageAction: {
setIcon: function(details) {
// This needs to run in the addon process because normalization requires
// the use of <canvas>.
let normalizedDetails = {
tabId: details.tabId,
path: IconDetails.normalize(details, context.extension, context),
};
return context.childManager.callParentAsyncFunction("pageAction.setIcon", [
normalizedDetails,
]);
},
},
};
});

Просмотреть файл

@ -260,9 +260,6 @@ extensions.registerSchemaAPI("pageAction", "addon_parent", context => {
setIcon(details) {
let tab = TabManager.getTab(details.tabId, context);
// Note: the caller in the child process has already normalized
// `details` to not contain an `imageData` property, so the icon can
// safely be normalized here without errors.
let icon = IconDetails.normalize(details, extension, context);
PageAction.for(extension).setProperty(tab, "icon", icon);
},

Просмотреть файл

@ -12,9 +12,7 @@ category webextension-scripts utils chrome://browser/content/ext-utils.js
category webextension-scripts windows chrome://browser/content/ext-windows.js
# scripts that must run in the same process as addon code.
category webextension-scripts-addon browserAction chrome://browser/content/ext-c-browserAction.js
category webextension-scripts-addon contextMenus chrome://browser/content/ext-c-contextMenus.js
category webextension-scripts-addon pageAction chrome://browser/content/ext-c-pageAction.js
category webextension-scripts-addon tabs chrome://browser/content/ext-c-tabs.js
# schemas

Просмотреть файл

@ -23,7 +23,5 @@ browser.jar:
content/browser/ext-tabs.js
content/browser/ext-utils.js
content/browser/ext-windows.js
content/browser/ext-c-browserAction.js
content/browser/ext-c-contextMenus.js
content/browser/ext-c-pageAction.js
content/browser/ext-c-tabs.js

Просмотреть файл

@ -60,6 +60,7 @@
"type": "object",
"isInstanceOf": "ImageData",
"additionalProperties": { "type": "any" },
"postprocess": "convertImageDataToURL",
"description": "Pixel data for an image. Must be an ImageData object (for example, from a <code>canvas</code> element)."
}
],

Просмотреть файл

@ -49,6 +49,7 @@
"type": "object",
"isInstanceOf": "ImageData",
"additionalProperties": { "type": "any" },
"postprocess": "convertImageDataToURL",
"description": "Pixel data for an image. Must be an ImageData object (for example, from a <code>canvas</code> element)."
}
],

Просмотреть файл

@ -648,12 +648,6 @@ BrowserGlue.prototype = {
this._sanitizer.onStartup();
// check if we're in safe mode
if (Services.appinfo.inSafeMode) {
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1231112#c7 . We need to
// register the observer early if we have to migrate tab groups
let currentUIVersion = 0;
try {
currentUIVersion = Services.prefs.getIntPref("browser.migration.version");
} catch (ex) {}
Services.ww.openWindow(null, "chrome://browser/content/safeMode.xul",
"_blank", "chrome,centerscreen,modal,resizable=no", null);
}

Просмотреть файл

@ -643,23 +643,6 @@ var PlacesOrganizer = {
if (selectedNode && !PlacesUtils.nodeIsSeparator(selectedNode)) {
detailsDeck.selectedIndex = 1;
// Using the concrete itemId is arguably wrong. The bookmarks API
// does allow setting properties for folder shortcuts as well, but since
// the UI does not distinct between the couple, we better just show
// the concrete item properties for shortcuts to root nodes.
let concreteId = PlacesUtils.getConcreteItemId(selectedNode);
var isRootItem = concreteId != -1 && PlacesUtils.isRootItem(concreteId);
var readOnly = isRootItem ||
selectedNode.parent.itemId == PlacesUIUtils.leftPaneFolderId;
var useConcreteId = isRootItem ||
PlacesUtils.nodeIsTagQuery(selectedNode);
var itemId = -1;
if (concreteId != -1 && useConcreteId)
itemId = concreteId;
else if (selectedNode.itemId != -1)
itemId = selectedNode.itemId;
else
itemId = PlacesUtils._uri(selectedNode.uri);
gEditItemOverlay.initPanel({ node: selectedNode
, hiddenRows: ["folderPicker"] });
@ -1059,9 +1042,6 @@ var ViewMenu = {
var popup = event.target;
var pivot = this._clean(popup, startID, endID);
// If no column is "sort-active", the "Unsorted" item needs to be checked,
// so track whether or not we find a column that is sort-active.
var isSorted = false;
var content = document.getElementById("placeContent");
var columns = content.columns;
for (var i = 0; i < columns.count; ++i) {
@ -1087,7 +1067,6 @@ var ViewMenu = {
// This column is the sort key. Its item is checked.
if (column.getAttribute("sortDirection") != "") {
menuitem.setAttribute("checked", "true");
isSorted = true;
}
}
else if (type == "checkbox") {

Просмотреть файл

@ -147,7 +147,6 @@ let gContainersManager = {
let icon = document.getElementById("icon").value;
let color = document.getElementById("color").value;
let name = document.getElementById("name").value;
let userContextId = false;
if (this.icons.indexOf(icon) == -1) {
throw "Internal error. The icon value doesn't match.";

Просмотреть файл

@ -526,7 +526,6 @@ var DirectoryLinksProvider = {
* @return download promise
*/
reportSitesAction: function DirectoryLinksProvider_reportSitesAction(sites, action, triggeringSiteIndex) {
let pastImpressions;
// Check if the suggested tile was shown
if (action == "view") {
sites.slice(0, triggeringSiteIndex + 1).filter(s => s).forEach(site => {
@ -544,13 +543,6 @@ var DirectoryLinksProvider = {
// suggested tile has targetedSite, or frecent_sites if it was pinned
let {frecent_sites, targetedSite, url} = sites[triggeringSiteIndex].link;
if (frecent_sites || targetedSite) {
// skip past_impressions for "unpin" to avoid chance of tracking
if (this._frequencyCaps[url] && action != "unpin") {
pastImpressions = {
total: this._frequencyCaps[url].totalViews,
daily: this._frequencyCaps[url].dailyViews
};
}
this._setFrequencyCapClick(url);
}
}

1
config/external/nss/nss.symbols поставляемый
Просмотреть файл

@ -692,6 +692,7 @@ SSL_SetSRTPCiphers
SSL_SetStapledOCSPResponses
SSL_SetURL
SSL_ShutdownServerSessionIDCache
SSL_SignatureSchemePrefSet
SSL_SNISocketConfigHook
SSL_VersionRangeGet
SSL_VersionRangeGetDefault

Просмотреть файл

@ -65,6 +65,7 @@ if CONFIG['MOZ_THUNDERBIRD'] or CONFIG['MOZ_SUITE']:
# Turn on SQLite's assertions in debug builds.
if CONFIG['MOZ_DEBUG']:
DEFINES['SQLITE_DEBUG'] = 1
DEFINES['SQLITE_ENABLE_API_ARMOR'] = True
if CONFIG['OS_TARGET'] == 'Android':
# default to user readable only to fit Android security model

Просмотреть файл

@ -24,8 +24,8 @@ const { require } = BrowserLoader({
window
});
const { createFactory, render, unmountComponentAtNode } =
require("devtools/client/shared/vendor/react");
const { createFactory } = require("devtools/client/shared/vendor/react");
const { render, unmountComponentAtNode } = require("devtools/client/shared/vendor/react-dom");
const AboutDebuggingApp = createFactory(require("./components/aboutdebugging"));

Просмотреть файл

@ -170,8 +170,8 @@ add_task(function* reloadButtonRefreshesMetadata() {
// Wait for the add-on list to be updated with the reloaded name.
const onReInstall = promiseAddonEvent("onInstalled");
const onAddonReloaded = waitForMutation(getAddonList(document),
{ childList: true, subtree: true });
const onAddonReloaded = waitForContentMutation(getAddonList(document));
const reloadButton = getReloadButton(document, manifestBase.name);
reloadButton.click();

Просмотреть файл

@ -39,7 +39,7 @@ add_task(function* () {
// Then wait for title update, but on slow test runner, the title may already
// be set to the expected value
if (newTabTarget.textContent != "foo") {
yield waitForMutation(newTabTarget, { childList: true });
yield waitForContentMutation(newTabTarget);
}
// Check that the new tab appears in the UI

Просмотреть файл

@ -3,7 +3,7 @@
/* eslint-env browser */
/* exported openAboutDebugging, changeAboutDebuggingHash, closeAboutDebugging,
installAddon, uninstallAddon, waitForMutation, assertHasTarget,
installAddon, uninstallAddon, waitForMutation, waitForContentMutation, assertHasTarget,
getServiceWorkerList, getTabList, openPanel, waitForInitialAddonList,
waitForServiceWorkerRegistered, unregisterServiceWorker,
waitForDelayedStartupFinished, setupTestAboutDebuggingWebExtension,
@ -229,6 +229,22 @@ function waitForMutation(target, mutationOptions) {
});
}
/**
* Returns a promise that will resolve after receiving a mutation in the subtree of the
* provided target. Depending on the current React implementation, a text change might be
* observable as a childList mutation or a characterData mutation.
*
* @param {Node} target
* @return {Promise}
*/
function waitForContentMutation(target) {
return waitForMutation(target, {
characterData: true,
childList: true,
subtree: true
});
}
/**
* Checks if an about:debugging TargetList element contains a Target element
* corresponding to the specified name.

Просмотреть файл

@ -42,7 +42,6 @@ var EventEmitter = require("devtools/shared/event-emitter");
*
* Events:
* "new-node-front" when the inner node changed
* "before-new-node-front" when the inner node is set to change
* "attribute-changed" when an attribute is changed
* "detached-front" when the node (or one of its parents) is removed from
* the document
@ -124,7 +123,6 @@ Selection.prototype = {
value = parentNode;
}
this.emit("before-new-node-front", value, reason);
this._nodeFront = value;
this.emit("new-node-front", value, this.reason);
},

Просмотреть файл

@ -38,5 +38,6 @@ add_task(function* () {
let console = yield toolbox.selectTool("webconsole");
let { jsterm } = console.hud;
let url = yield jsterm.execute("document.location.href");
is(url.textContent, URL_2, "The console inspects the second document");
// Uses includes as the old console frontend prints a timestamp
ok(url.textContent.includes(URL_2), "The console inspects the second document");
});

Просмотреть файл

@ -103,7 +103,6 @@ function Inspector(toolbox) {
this.onTextBoxContextMenu = this.onTextBoxContextMenu.bind(this);
this._updateSearchResultsLabel = this._updateSearchResultsLabel.bind(this);
this.onNewSelection = this.onNewSelection.bind(this);
this.onBeforeNewSelection = this.onBeforeNewSelection.bind(this);
this.onDetached = this.onDetached.bind(this);
this.onPaneToggleButtonClicked = this.onPaneToggleButtonClicked.bind(this);
this._onMarkupFrameLoad = this._onMarkupFrameLoad.bind(this);
@ -223,7 +222,6 @@ Inspector.prototype = {
this.walker.on("new-root", this.onNewRoot);
this.selection.on("new-node-front", this.onNewSelection);
this.selection.on("before-new-node-front", this.onBeforeNewSelection);
this.selection.on("detached-front", this.onDetached);
if (this.target.isLocalTab) {
@ -855,16 +853,6 @@ Inspector.prototype = {
this._updateProgress = null;
},
/**
* When a new node is selected, before the selection has changed.
*/
onBeforeNewSelection: function (event, node) {
if (this.breadcrumbs.indexOf(node) == -1) {
// only clear locks if we'd have to update breadcrumbs
this.clearPseudoClasses();
}
},
/**
* When a node is deleted, select its parent node or the defaultNode if no
* parent is found (may happen when deleting an iframe inside which the
@ -928,7 +916,6 @@ Inspector.prototype = {
this.teardownToolbar();
this.breadcrumbs.destroy();
this.selection.off("new-node-front", this.onNewSelection);
this.selection.off("before-new-node-front", this.onBeforeNewSelection);
this.selection.off("detached-front", this.onDetached);
let markupDestroyer = this._destroyMarkup();
this.panelWin.inspector = null;
@ -1557,16 +1544,6 @@ Inspector.prototype = {
});
},
/**
* Clear any pseudo-class locks applied to the current hierarchy.
*/
clearPseudoClasses: function () {
if (!this.walker) {
return promise.resolve();
}
return this.walker.clearPseudoClassLocks().catch(this._handleRejectionIfNotDestroyed);
},
/**
* Edit the outerHTML of the selected Node.
*/

Просмотреть файл

@ -31,15 +31,29 @@ add_task(function* () {
yield selectNode("#div-1", inspector);
yield togglePseudoClass(inspector);
yield assertPseudoAddedToNode(inspector, testActor, view);
yield assertPseudoAddedToNode(inspector, testActor, view, "#div-1");
yield togglePseudoClass(inspector);
yield assertPseudoRemovedFromNode(testActor);
yield assertPseudoRemovedFromView(inspector, testActor, view);
yield assertPseudoRemovedFromNode(testActor, "#div-1");
yield assertPseudoRemovedFromView(inspector, testActor, view, "#div-1");
yield togglePseudoClass(inspector);
yield testNavigate(inspector, testActor, view);
info("Toggle pseudo on the parent and ensure everything is toggled off");
yield selectNode("#parent-div", inspector);
yield togglePseudoClass(inspector);
yield assertPseudoRemovedFromNode(testActor, "#div-1");
yield assertPseudoRemovedFromView(inspector, testActor, view, "#div-1");
yield togglePseudoClass(inspector);
info("Assert pseudo is dismissed when toggling it on a sibling node");
yield selectNode("#div-2", inspector);
yield togglePseudoClass(inspector);
yield assertPseudoAddedToNode(inspector, testActor, view, "#div-2");
let hasLock = yield testActor.hasPseudoClassLock("#div-1", PSEUDO);
ok(!hasLock, "pseudo-class lock has been removed for the previous locked node");
info("Destroying the toolbox");
let tab = toolbox.target.tab;
yield toolbox.destroy();
@ -47,7 +61,8 @@ add_task(function* () {
// As the toolbox get detroyed, we need to fetch a new test-actor
testActor = yield getTestActorWithoutToolbox(tab);
yield assertPseudoRemovedFromNode(testActor);
yield assertPseudoRemovedFromNode(testActor, "#div-1");
yield assertPseudoRemovedFromNode(testActor, "#div-2");
});
function* togglePseudoClass(inspector) {
@ -75,17 +90,14 @@ function* testNavigate(inspector, testActor, ruleview) {
ok((yield testActor.hasPseudoClassLock("#div-1", PSEUDO)),
"pseudo-class lock is still applied after inspecting ancestor");
let onPseudo = inspector.selection.once("pseudoclass");
yield selectNode("#div-2", inspector);
yield onPseudo;
info("Make sure the pseudoclass is removed after navigating to a " +
info("Make sure the pseudoclass is still set after navigating to a " +
"non-hierarchy node");
ok(!(yield testActor.hasPseudoClassLock("#div-1", PSEUDO)),
"pseudo-class lock is removed after inspecting sibling node");
ok(yield testActor.hasPseudoClassLock("#div-1", PSEUDO),
"pseudo-class lock is still on after inspecting sibling node");
yield selectNode("#div-1", inspector);
yield togglePseudoClass(inspector);
}
function* showPickerOn(selector, inspector) {
@ -93,10 +105,10 @@ function* showPickerOn(selector, inspector) {
yield inspector.highlighter.showBoxModel(nodeFront);
}
function* assertPseudoAddedToNode(inspector, testActor, ruleview) {
info("Make sure the pseudoclass lock is applied to #div-1 and its ancestors");
function* assertPseudoAddedToNode(inspector, testActor, ruleview, selector) {
info("Make sure the pseudoclass lock is applied to " + selector + " and its ancestors");
let hasLock = yield testActor.hasPseudoClassLock("#div-1", PSEUDO);
let hasLock = yield testActor.hasPseudoClassLock(selector, PSEUDO);
ok(hasLock, "pseudo-class lock has been applied");
hasLock = yield testActor.hasPseudoClassLock("#parent-div", PSEUDO);
ok(hasLock, "pseudo-class lock has been applied");
@ -111,8 +123,8 @@ function* assertPseudoAddedToNode(inspector, testActor, ruleview) {
is(rules[1]._ruleEditor.rule.selectorText, "div:hover",
"rule view is showing " + PSEUDO + " rule");
info("Show the highlighter on #div-1");
yield showPickerOn("#div-1", inspector);
info("Show the highlighter on " + selector);
yield showPickerOn(selector, inspector);
info("Check that the infobar selector contains the pseudo-class");
let value = yield testActor.getHighlighterNodeTextContent(
@ -121,11 +133,11 @@ function* assertPseudoAddedToNode(inspector, testActor, ruleview) {
yield inspector.highlighter.hideBoxModel();
}
function* assertPseudoRemovedFromNode(testActor) {
function* assertPseudoRemovedFromNode(testActor, selector) {
info("Make sure the pseudoclass lock is removed from #div-1 and its " +
"ancestors");
let hasLock = yield testActor.hasPseudoClassLock("#div-1", PSEUDO);
let hasLock = yield testActor.hasPseudoClassLock(selector, PSEUDO);
ok(!hasLock, "pseudo-class lock has been removed");
hasLock = yield testActor.hasPseudoClassLock("#parent-div", PSEUDO);
ok(!hasLock, "pseudo-class lock has been removed");
@ -133,13 +145,13 @@ function* assertPseudoRemovedFromNode(testActor) {
ok(!hasLock, "pseudo-class lock has been removed");
}
function* assertPseudoRemovedFromView(inspector, testActor, ruleview) {
function* assertPseudoRemovedFromView(inspector, testActor, ruleview, selector) {
info("Check that the ruleview no longer contains the pseudo-class rule");
let rules = ruleview.element.querySelectorAll(
".ruleview-rule.theme-separator");
is(rules.length, 2, "rule view is showing 2 rules after removing lock");
yield showPickerOn("#div-1", inspector);
yield showPickerOn(selector, inspector);
let value = yield testActor.getHighlighterNodeTextContent(
"box-model-infobar-pseudo-classes");

Просмотреть файл

@ -584,6 +584,22 @@ const Services = {
}
},
},
/**
* An implementation of Services.wm that provides a shim for
* getMostRecentWindow.
*/
wm: {
getMostRecentWindow: function () {
// Having the returned object implement openUILinkIn is
// sufficient for our purposes.
return {
openUILinkIn: function (url) {
window.open(url, "_blank");
},
};
},
},
};
/**

Просмотреть файл

@ -0,0 +1,20 @@
<!DOCTYPE HTML>
<html>
<head>
<script>
// Silence eslint complaint about the onload below.
/* eslint-disable no-unused-vars */
"use strict";
function load() {
(window.opener || window.parent).hurray();
window.close();
}
</script>
</head>
<body onload='load()'>
</body>
</html>

Просмотреть файл

@ -1,8 +1,10 @@
[DEFAULT]
support-files =
file_service_wm.html
prefs-wrapper.js
[test_service_appinfo.html]
[test_service_focus.html]
[test_service_prefs.html]
[test_service_prefs_defaults.html]
[test_service_wm.html]

Просмотреть файл

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1310279
-->
<head>
<title>Test for Bug 1310279 - replace Services.wm</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript;version=1.8">
"use strict";
var exports = {}
var module = {exports};
</script>
<script type="application/javascript;version=1.8"
src="resource://devtools/client/shared/shim/Services.js"></script>
</head>
<body>
<script type="application/javascript;version=1.8">
"use strict";
function hurray(window) {
ok(true, "window loaded");
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
Services.wm.getMostRecentWindow().openUILinkIn("file_service_wm.html");
</script>
</body>

Просмотреть файл

@ -4,5 +4,6 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DIRS += [
'stub-generators'
'stub-generators',
'stubs'
]

Просмотреть файл

@ -18,18 +18,120 @@ registerCleanupFunction(() => {
});
const { prepareMessage } = require("devtools/client/webconsole/new-console-output/utils/messages");
const { stubPackets } = require("devtools/client/webconsole/new-console-output/test/fixtures/stubs/index.js");
const BASE_PATH = "../../../../devtools/client/webconsole/new-console-output/test/fixtures";
const TEMP_FILE_PATH = OS.Path.join(`${BASE_PATH}/stub-generators`, "test-tempfile.js");
let cachedPackets = {};
function getCleanedPacket(key, packet) {
if(Object.keys(cachedPackets).includes(key)) {
return cachedPackets[key];
}
// Strip escaped characters.
let safeKey = key
.replace(/\\n/g, "\n")
.replace(/\\r/g, "\r")
.replace(/\\\"/g, `\"`)
.replace(/\\\'/g, `\'`);
// If the stub already exist, we want to ignore irrelevant properties
// (actor, timeStamp, timer, ...) that might changed and "pollute"
// the diff resulting from this stub generation.
let res;
if(stubPackets.has(safeKey)) {
let existingPacket = stubPackets.get(safeKey);
res = Object.assign({}, packet, {
from: existingPacket.from
});
// Clean root timestamp.
if(res.timestamp) {
res.timestamp = existingPacket.timestamp;
}
if (res.message) {
// Clean timeStamp on the message prop.
res.message.timeStamp = existingPacket.message.timeStamp;
if (res.message.timer) {
// Clean timer properties on the message.
// Those properties are found on console.time and console.timeEnd calls,
// and those time can vary, which is why we need to clean them.
if (res.message.timer.started) {
res.message.timer.started = existingPacket.message.timer.started;
}
if (res.message.timer.duration) {
res.message.timer.duration = existingPacket.message.timer.duration;
}
}
if(Array.isArray(res.message.arguments)) {
// Clean actor ids on each message.arguments item.
res.message.arguments.forEach((argument, i) => {
if (argument && argument.actor) {
argument.actor = existingPacket.message.arguments[i].actor;
}
});
}
}
if (res.result) {
// Clean actor ids on evaluation result messages.
res.result.actor = existingPacket.result.actor;
if (res.result.preview) {
if(res.result.preview.timestamp) {
// Clean timestamp there too.
res.result.preview.timestamp = existingPacket.result.preview.timestamp;
}
}
}
if (res.exception) {
// Clean actor ids on exception messages.
res.exception.actor = existingPacket.exception.actor;
if (res.exception.preview) {
if(res.exception.preview.timestamp) {
// Clean timestamp there too.
res.exception.preview.timestamp = existingPacket.exception.preview.timestamp;
}
}
}
if (res.eventActor) {
// Clean actor ids, timeStamp and startedDateTime on network messages.
res.eventActor.actor = existingPacket.eventActor.actor;
res.eventActor.startedDateTime = existingPacket.eventActor.startedDateTime;
res.eventActor.timeStamp = existingPacket.eventActor.timeStamp;
}
if (res.pageError) {
// Clean timeStamp on pageError messages.
res.pageError.timeStamp = existingPacket.pageError.timeStamp;
}
} else {
res = packet;
}
cachedPackets[key] = res;
return res;
}
function formatPacket(key, packet) {
return `
stubPackets.set("${key}", ${JSON.stringify(packet, null, "\t")});
stubPackets.set("${key}", ${JSON.stringify(getCleanedPacket(key, packet), null, "\t")});
`;
}
function formatStub(key, message) {
let prepared = prepareMessage(message, {getNextId: () => "1"});
function formatStub(key, packet) {
let prepared = prepareMessage(
getCleanedPacket(key, packet),
{getNextId: () => "1"}
);
return `
stubPreparedMessages.set("${key}", new ConsoleMessage(${JSON.stringify(prepared, null, "\t")}));
`;

Просмотреть файл

@ -0,0 +1,11 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
'consoleApi.js',
'evaluationResult.js',
'index.js',
'networkEvent.js',
'pageError.js',
)

Просмотреть файл

@ -1752,6 +1752,14 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
return;
}
// There can be only one node locked per pseudo, so dismiss all existing
// ones
for (let locked of this._activePseudoClassLocks) {
if (DOMUtils.hasPseudoClassLock(locked.rawNode, pseudo)) {
this._removePseudoClassLock(locked, pseudo);
}
}
this._addPseudoClassLock(node, pseudo);
if (!options.parents) {
@ -1836,6 +1844,15 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
this._removePseudoClassLock(node, pseudo);
// Remove pseudo class for children as we don't want to allow
// turning it on for some childs without setting it on some parents
for (let locked of this._activePseudoClassLocks) {
if (node.rawNode.contains(locked.rawNode) &&
DOMUtils.hasPseudoClassLock(locked.rawNode, pseudo)) {
this._removePseudoClassLock(locked, pseudo);
}
}
if (!options.parents) {
return;
}

Просмотреть файл

@ -46,6 +46,14 @@ KeyframeEffect::Constructor(
aOptions, aRv);
}
/* static */ already_AddRefed<KeyframeEffect>
KeyframeEffect::Constructor(const GlobalObject& aGlobal,
KeyframeEffectReadOnly& aSource,
ErrorResult& aRv)
{
return ConstructKeyframeEffect<KeyframeEffect>(aGlobal, aSource, aRv);
}
/* static */ already_AddRefed<KeyframeEffect>
KeyframeEffect::Constructor(
const GlobalObject& aGlobal,

Просмотреть файл

@ -47,6 +47,11 @@ public:
const UnrestrictedDoubleOrKeyframeEffectOptions& aOptions,
ErrorResult& aRv);
static already_AddRefed<KeyframeEffect>
Constructor(const GlobalObject& aGlobal,
KeyframeEffectReadOnly& aSource,
ErrorResult& aRv);
// Variant of Constructor that accepts a KeyframeAnimationOptions object
// for use with for Animatable.animate.
// Not exposed to content.

Просмотреть файл

@ -273,40 +273,7 @@ KeyframeEffectReadOnly::UpdateProperties(nsStyleContext* aStyleContext)
{
MOZ_ASSERT(aStyleContext);
nsTArray<AnimationProperty> properties;
if (mTarget) {
// When GetComputedKeyframeValues or GetAnimationPropertiesFromKeyframes
// calculate computed values from |mKeyframes|, they could possibly
// trigger a subsequent restyle in which we rebuild animations. If that
// happens we could find that |mKeyframes| is overwritten while it is
// being iterated over. Normally that shouldn't happen but just in case we
// make a copy of |mKeyframes| first and iterate over that instead.
auto keyframesCopy(mKeyframes);
nsTArray<ComputedKeyframeValues> computedValues =
KeyframeUtils::GetComputedKeyframeValues(keyframesCopy,
mTarget->mElement,
aStyleContext);
if (mEffectOptions.mSpacingMode == SpacingMode::paced) {
KeyframeUtils::ApplySpacing(keyframesCopy, SpacingMode::paced,
mEffectOptions.mPacedProperty,
computedValues, aStyleContext);
}
properties =
KeyframeUtils::GetAnimationPropertiesFromKeyframes(keyframesCopy,
computedValues,
aStyleContext);
#ifdef DEBUG
MOZ_ASSERT(SpecifiedKeyframeArraysAreEqual(mKeyframes, keyframesCopy),
"Apart from the computed offset members, the keyframes array"
" should not be modified");
#endif
mKeyframes.SwapElements(keyframesCopy);
}
nsTArray<AnimationProperty> properties = BuildProperties(aStyleContext);
if (mProperties == properties) {
return;
@ -613,6 +580,87 @@ KeyframeEffectReadOnly::ConstructKeyframeEffect(
return effect.forget();
}
template<class KeyframeEffectType>
/* static */ already_AddRefed<KeyframeEffectType>
KeyframeEffectReadOnly::ConstructKeyframeEffect(const GlobalObject& aGlobal,
KeyframeEffectReadOnly& aSource,
ErrorResult& aRv)
{
nsIDocument* doc = AnimationUtils::GetCurrentRealmDocument(aGlobal.Context());
if (!doc) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
// Create a new KeyframeEffectReadOnly object with aSource's target,
// iteration composite operation, composite operation, and spacing mode.
// The constructor creates a new AnimationEffect(ReadOnly) object by
// aSource's TimingParams.
// Note: we don't need to re-throw exceptions since the value specified on
// aSource's timing object can be assumed valid.
RefPtr<KeyframeEffectType> effect =
new KeyframeEffectType(doc,
aSource.mTarget,
aSource.SpecifiedTiming(),
aSource.mEffectOptions);
// Copy cumulative change hint. mCumulativeChangeHint should be the same as
// the source one because both of targets are the same.
effect->mCumulativeChangeHint = aSource.mCumulativeChangeHint;
// Copy aSource's keyframes and animation properties.
// Note: We don't call SetKeyframes directly, which might revise the
// computed offsets and rebuild the animation properties.
// FIXME: Bug 1314537: We have to make sure SharedKeyframeList is handled
// properly.
effect->mKeyframes = aSource.mKeyframes;
effect->mProperties = aSource.mProperties;
return effect.forget();
}
nsTArray<AnimationProperty>
KeyframeEffectReadOnly::BuildProperties(nsStyleContext* aStyleContext)
{
MOZ_ASSERT(aStyleContext);
nsTArray<AnimationProperty> result;
// If mTarget is null, return an empty property array.
if (!mTarget) {
return result;
}
// When GetComputedKeyframeValues or GetAnimationPropertiesFromKeyframes
// calculate computed values from |mKeyframes|, they could possibly
// trigger a subsequent restyle in which we rebuild animations. If that
// happens we could find that |mKeyframes| is overwritten while it is
// being iterated over. Normally that shouldn't happen but just in case we
// make a copy of |mKeyframes| first and iterate over that instead.
auto keyframesCopy(mKeyframes);
nsTArray<ComputedKeyframeValues> computedValues =
KeyframeUtils::GetComputedKeyframeValues(keyframesCopy,
mTarget->mElement,
aStyleContext);
if (mEffectOptions.mSpacingMode == SpacingMode::paced) {
KeyframeUtils::ApplySpacing(keyframesCopy, SpacingMode::paced,
mEffectOptions.mPacedProperty,
computedValues, aStyleContext);
}
result = KeyframeUtils::GetAnimationPropertiesFromKeyframes(keyframesCopy,
computedValues,
aStyleContext);
#ifdef DEBUG
MOZ_ASSERT(SpecifiedKeyframeArraysAreEqual(mKeyframes, keyframesCopy),
"Apart from the computed offset members, the keyframes array"
" should not be modified");
#endif
mKeyframes.SwapElements(keyframesCopy);
return result;
}
void
KeyframeEffectReadOnly::UpdateTargetRegistration()
{
@ -716,6 +764,14 @@ KeyframeEffectReadOnly::Constructor(
aRv);
}
/* static */ already_AddRefed<KeyframeEffectReadOnly>
KeyframeEffectReadOnly::Constructor(const GlobalObject& aGlobal,
KeyframeEffectReadOnly& aSource,
ErrorResult& aRv)
{
return ConstructKeyframeEffect<KeyframeEffectReadOnly>(aGlobal, aSource, aRv);
}
void
KeyframeEffectReadOnly::GetTarget(
Nullable<OwningElementOrCSSPseudoElement>& aRv) const

Просмотреть файл

@ -121,14 +121,16 @@ struct AnimationPropertySegment
StyleAnimationValue mFromValue, mToValue;
Maybe<ComputedTimingFunction> mTimingFunction;
bool operator==(const AnimationPropertySegment& aOther) const {
bool operator==(const AnimationPropertySegment& aOther) const
{
return mFromKey == aOther.mFromKey &&
mToKey == aOther.mToKey &&
mFromValue == aOther.mFromValue &&
mToValue == aOther.mToValue &&
mTimingFunction == aOther.mTimingFunction;
}
bool operator!=(const AnimationPropertySegment& aOther) const {
bool operator!=(const AnimationPropertySegment& aOther) const
{
return !(*this == aOther);
}
};
@ -152,17 +154,31 @@ struct AnimationProperty
InfallibleTArray<AnimationPropertySegment> mSegments;
// The copy constructor/assignment doesn't copy mIsRunningOnCompositor and
// mPerformanceWarning.
AnimationProperty() = default;
AnimationProperty(const AnimationProperty& aOther)
: mProperty(aOther.mProperty), mSegments(aOther.mSegments) { }
AnimationProperty& operator=(const AnimationProperty& aOther)
{
mProperty = aOther.mProperty;
mSegments = aOther.mSegments;
return *this;
}
// NOTE: This operator does *not* compare the mIsRunningOnCompositor member.
// This is because AnimationProperty objects are compared when recreating
// CSS animations to determine if mutation observer change records need to
// be created or not. However, at the point when these objects are compared
// the mIsRunningOnCompositor will not have been set on the new objects so
// we ignore this member to avoid generating spurious change records.
bool operator==(const AnimationProperty& aOther) const {
bool operator==(const AnimationProperty& aOther) const
{
return mProperty == aOther.mProperty &&
mSegments == aOther.mSegments;
}
bool operator!=(const AnimationProperty& aOther) const {
bool operator!=(const AnimationProperty& aOther) const
{
return !(*this == aOther);
}
};
@ -198,6 +214,11 @@ public:
const UnrestrictedDoubleOrKeyframeEffectOptions& aOptions,
ErrorResult& aRv);
static already_AddRefed<KeyframeEffectReadOnly>
Constructor(const GlobalObject& aGlobal,
KeyframeEffectReadOnly& aSource,
ErrorResult& aRv);
void GetTarget(Nullable<OwningElementOrCSSPseudoElement>& aRv) const;
Maybe<NonOwningAnimationTarget> GetTarget() const
{
@ -320,6 +341,17 @@ protected:
const OptionsType& aOptions,
ErrorResult& aRv);
template<class KeyframeEffectType>
static already_AddRefed<KeyframeEffectType>
ConstructKeyframeEffect(const GlobalObject& aGlobal,
KeyframeEffectReadOnly& aSource,
ErrorResult& aRv);
// Build properties by recalculating from |mKeyframes| using |aStyleContext|
// to resolve specified values. This function also applies paced spacing if
// needed.
nsTArray<AnimationProperty> BuildProperties(nsStyleContext* aStyleContext);
// This effect is registered with its target element so long as:
//
// (a) It has a target element, and

Просмотреть файл

@ -162,7 +162,7 @@ AudioChannelAgent::InitInternal(nsPIDOMWindowInner* aWindow,
}
if (NS_WARN_IF(!aWindow)) {
return NS_OK;
return NS_ERROR_FAILURE;
}
MOZ_ASSERT(aWindow->IsInnerWindow());

Просмотреть файл

@ -469,10 +469,6 @@ include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
for var in ('MOZ_B2G_RIL'):
if CONFIG[var]:
DEFINES[var] = True
if CONFIG['MOZ_BUILD_APP'] in ['browser', 'mobile/android', 'xulrunner']:
DEFINES['HAVE_SIDEBAR'] = True

Просмотреть файл

@ -1304,7 +1304,9 @@ HTMLCanvasElement::GetCompositorBackendType() const
nsIWidget* docWidget = nsContentUtils::WidgetForDocument(OwnerDoc());
if (docWidget) {
layers::LayerManager* layerManager = docWidget->GetLayerManager();
return layerManager->GetCompositorBackendType();
if (layerManager) {
return layerManager->GetCompositorBackendType();
}
}
return LayersBackend::LAYERS_NONE;

Просмотреть файл

@ -2952,7 +2952,7 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNo
mWatchManager.Watch(mReadyState, &HTMLMediaElement::UpdateReadyStateInternal);
mShutdownObserver->Subscribe(this);
CreateAudioChannelAgent();
MaybeCreateAudioChannelAgent();
}
HTMLMediaElement::~HTMLMediaElement()
@ -2993,6 +2993,7 @@ HTMLMediaElement::~HTMLMediaElement()
}
WakeLockRelease();
mAudioChannelAgent = nullptr;
}
void HTMLMediaElement::StopSuspendingAfterFirstFrame()
@ -3752,10 +3753,6 @@ nsresult HTMLMediaElement::InitializeDecoderAsClone(MediaDecoder* aOriginal)
LOG(LogLevel::Debug, ("%p Cloned decoder %p from %p", this, decoder.get(), aOriginal));
decoder->SetMediaSeekable(aOriginal->IsMediaSeekable());
decoder->SetMediaSeekableOnlyInBufferedRanges(
aOriginal->IsMediaSeekableOnlyInBufferedRanges());
RefPtr<MediaResource> resource =
originalResource->CloneData(decoder->GetResourceCallback());
@ -5759,17 +5756,26 @@ ImageContainer* HTMLMediaElement::GetImageContainer()
return container ? container->GetImageContainer() : nullptr;
}
void
HTMLMediaElement::CreateAudioChannelAgent()
bool
HTMLMediaElement::MaybeCreateAudioChannelAgent()
{
if (mAudioChannelAgent) {
return;
return true;
}
mAudioChannelAgent = new AudioChannelAgent();
mAudioChannelAgent->InitWithWeakCallback(OwnerDoc()->GetInnerWindow(),
nsresult rv = mAudioChannelAgent->InitWithWeakCallback(OwnerDoc()->GetInnerWindow(),
static_cast<int32_t>(mAudioChannel),
this);
if (NS_WARN_IF(NS_FAILED(rv))) {
mAudioChannelAgent = nullptr;
MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
("HTMLMediaElement, Fail to initialize the audio channel agent,"
" this = %p\n", this));
return false;
}
return true;
}
bool
@ -5825,6 +5831,10 @@ HTMLMediaElement::UpdateAudioChannelPlayingState(bool aForcePlaying)
aForcePlaying || IsPlayingThroughTheAudioChannel();
if (playingThroughTheAudioChannel != mPlayingThroughTheAudioChannel) {
if (!MaybeCreateAudioChannelAgent()) {
return;
}
mPlayingThroughTheAudioChannel = playingThroughTheAudioChannel;
NotifyAudioChannelAgent(mPlayingThroughTheAudioChannel);
}
@ -6035,7 +6045,7 @@ HTMLMediaElement::IsAllowedToPlay()
// If the tab hasn't been activated yet, the media element in that tab can't
// be playback now until the tab goes to foreground first time or user clicks
// the unblocking tab icon.
if (!IsTabActivated()) {
if (MaybeCreateAudioChannelAgent() && !IsTabActivated()) {
// Even we haven't start playing yet, we still need to notify the audio
// channe system because we need to receive the resume notification later.
UpdateAudioChannelPlayingState(true /* force to start */);
@ -6048,6 +6058,7 @@ HTMLMediaElement::IsAllowedToPlay()
bool
HTMLMediaElement::IsTabActivated() const
{
MOZ_ASSERT(mAudioChannelAgent);
return !mAudioChannelAgent->ShouldBlockMedia();
}
@ -6459,9 +6470,8 @@ HTMLMediaElement::SetAudibleState(bool aAudible)
void
HTMLMediaElement::NotifyAudioPlaybackChanged(AudibleChangedReasons aReason)
{
MOZ_ASSERT(mAudioChannelAgent);
if (!mAudioChannelAgent->IsPlayingStarted()) {
if (MaybeCreateAudioChannelAgent() &&
!mAudioChannelAgent->IsPlayingStarted()) {
return;
}
@ -6504,6 +6514,7 @@ HTMLMediaElement::MaybeNotifyMediaResumed(SuspendTypes aSuspend)
return;
}
MOZ_ASSERT(mAudioChannelAgent);
uint64_t windowID = mAudioChannelAgent->WindowID();
NS_DispatchToMainThread(NS_NewRunnableFunction([windowID]() -> void {
nsCOMPtr<nsIObserverService> observerService =
@ -6580,14 +6591,13 @@ HTMLMediaElement::SetMediaInfo(const MediaInfo& aInfo)
void
HTMLMediaElement::AudioCaptureStreamChangeIfNeeded()
{
MOZ_ASSERT(mAudioChannelAgent);
// No need to capture a silence media element.
if (!HasAudio()) {
return;
}
if (!mAudioChannelAgent->IsPlayingStarted()) {
if (MaybeCreateAudioChannelAgent() &&
!mAudioChannelAgent->IsPlayingStarted()) {
return;
}

Просмотреть файл

@ -1229,9 +1229,11 @@ protected:
// Notifies the audio channel agent when the element starts or stops playing.
void NotifyAudioChannelAgent(bool aPlaying);
// Creates the audio channel agent in the beginning and this agent would be
// used to communicate with the AudioChannelService.
void CreateAudioChannelAgent();
// True if we create the audio channel agent successfully or we already have
// one. The agent is used to communicate with the AudioChannelService. eg.
// notify we are playing/audible and receive muted/unmuted/suspend/resume
// commands from AudioChannelService.
bool MaybeCreateAudioChannelAgent();
// Determine if the element should be paused because of suspend conditions.
bool ShouldElementBePaused();

Просмотреть файл

@ -171,15 +171,6 @@ MediaDecoder::ResourceCallback::SetInfinite(bool aInfinite)
}
}
void
MediaDecoder::ResourceCallback::SetMediaSeekable(bool aMediaSeekable)
{
MOZ_ASSERT(NS_IsMainThread());
if (mDecoder) {
mDecoder->SetMediaSeekable(aMediaSeekable);
}
}
void
MediaDecoder::ResourceCallback::NotifyNetworkError()
{
@ -406,8 +397,6 @@ MediaDecoder::MediaDecoder(MediaDecoderOwner* aOwner)
, INIT_CANONICAL(mPlaybackBytesPerSecond, 0.0)
, INIT_CANONICAL(mPlaybackRateReliable, true)
, INIT_CANONICAL(mDecoderPosition, 0)
, INIT_CANONICAL(mMediaSeekable, true)
, INIT_CANONICAL(mMediaSeekableOnlyInBufferedRanges, false)
, INIT_CANONICAL(mIsVisible, !aOwner->IsHidden())
, mTelemetryReported(false)
{
@ -791,8 +780,8 @@ MediaDecoder::MetadataLoaded(nsAutoPtr<MediaInfo> aInfo,
aInfo->mAudio.mChannels, aInfo->mAudio.mRate,
aInfo->HasAudio(), aInfo->HasVideo());
SetMediaSeekable(aInfo->mMediaSeekable);
SetMediaSeekableOnlyInBufferedRanges(aInfo->mMediaSeekableOnlyInBufferedRanges);
mMediaSeekable = aInfo->mMediaSeekable;
mMediaSeekableOnlyInBufferedRanges = aInfo->mMediaSeekableOnlyInBufferedRanges;
mInfo = aInfo.forget();
ConstructMediaTracks();
@ -1286,18 +1275,6 @@ MediaDecoder::UpdateEstimatedMediaDuration(int64_t aDuration)
mEstimatedDuration = Some(TimeUnit::FromMicroseconds(aDuration));
}
void
MediaDecoder::SetMediaSeekable(bool aMediaSeekable) {
MOZ_ASSERT(NS_IsMainThread());
mMediaSeekable = aMediaSeekable;
}
void
MediaDecoder::SetMediaSeekableOnlyInBufferedRanges(bool aMediaSeekableOnlyInBufferedRanges){
MOZ_ASSERT(NS_IsMainThread());
mMediaSeekableOnlyInBufferedRanges = aMediaSeekableOnlyInBufferedRanges;
}
bool
MediaDecoder::IsTransportSeekable()
{
@ -1313,13 +1290,6 @@ MediaDecoder::IsMediaSeekable()
return mMediaSeekable;
}
bool
MediaDecoder::IsMediaSeekableOnlyInBufferedRanges()
{
MOZ_ASSERT(NS_IsMainThread());
return mMediaSeekableOnlyInBufferedRanges;
}
media::TimeIntervals
MediaDecoder::GetSeekable()
{
@ -1333,7 +1303,7 @@ MediaDecoder::GetSeekable()
// We can seek in buffered range if the media is seekable. Also, we can seek
// in unbuffered ranges if the transport level is seekable (local file or the
// server supports range requests, etc.) or in cue-less WebMs
if (IsMediaSeekableOnlyInBufferedRanges()) {
if (mMediaSeekableOnlyInBufferedRanges) {
return GetBuffered();
} else if (!IsMediaSeekable()) {
return media::TimeIntervals();

Просмотреть файл

@ -82,7 +82,6 @@ public:
/* MediaResourceCallback functions */
MediaDecoderOwner* GetMediaOwner() const override;
void SetInfinite(bool aInfinite) override;
void SetMediaSeekable(bool aMediaSeekable) override;
void NotifyNetworkError() override;
void NotifyDecodeError() override;
void NotifyDataArrived() override;
@ -252,17 +251,9 @@ protected:
void UpdateEstimatedMediaDuration(int64_t aDuration) override;
public:
// Set a flag indicating whether random seeking is supported
void SetMediaSeekable(bool aMediaSeekable);
// Set a flag indicating whether seeking is supported only in buffered ranges
void SetMediaSeekableOnlyInBufferedRanges(bool aMediaSeekableOnlyInBufferedRanges);
// Returns true if this media supports random seeking. False for example with
// chained ogg files.
bool IsMediaSeekable();
// Returns true if this media supports seeking only in buffered ranges. True
// for example in WebMs with no cues
bool IsMediaSeekableOnlyInBufferedRanges();
// Returns true if seeking is supported on a transport level (e.g. the server
// supports range requests, we are playing a file, etc.).
bool IsTransportSeekable();
@ -573,7 +564,7 @@ private:
void OnMediaNotSeekable()
{
SetMediaSeekable(false);
mMediaSeekable = false;
}
void FinishShutdown();
@ -669,6 +660,13 @@ protected:
// True if we've already fired metadataloaded.
bool mFiredMetadataLoaded;
// True if the media is seekable (i.e. supports random access).
bool mMediaSeekable = true;
// True if the media is only seekable within its buffered ranges
// like WebMs with no cues.
bool mMediaSeekableOnlyInBufferedRanges = false;
// Stores media info, including info of audio tracks and video tracks, should
// only be accessed from main thread.
nsAutoPtr<MediaInfo> mInfo;
@ -768,12 +766,6 @@ protected:
// back again.
Canonical<int64_t> mDecoderPosition;
// True if the media is seekable (i.e. supports random access).
Canonical<bool> mMediaSeekable;
// True if the media is only seekable within its buffered ranges.
Canonical<bool> mMediaSeekableOnlyInBufferedRanges;
// True if the decoder is visible.
Canonical<bool> mIsVisible;
@ -815,12 +807,6 @@ public:
AbstractCanonical<int64_t>* CanonicalDecoderPosition() {
return &mDecoderPosition;
}
AbstractCanonical<bool>* CanonicalMediaSeekable() {
return &mMediaSeekable;
}
AbstractCanonical<bool>* CanonicalMediaSeekableOnlyInBufferedRanges() {
return &mMediaSeekableOnlyInBufferedRanges;
}
AbstractCanonical<bool>* CanonicalIsVisible() {
return &mIsVisible;
}

Просмотреть файл

@ -193,26 +193,15 @@ public:
virtual State GetState() const = 0;
// Event handlers for various events.
// Return true if the event is handled by this state object.
virtual bool HandleDormant(bool aDormant);
virtual bool HandleCDMProxyReady() { return false; }
virtual bool HandleAudioDecoded(MediaData* aAudio) { return false; }
virtual bool HandleVideoDecoded(MediaData* aVideo, TimeStamp aDecodeStart)
{
return false;
}
virtual bool HandleEndOfStream() { return false; }
virtual bool HandleWaitingForData() { return false; }
virtual void HandleCDMProxyReady() {}
virtual void HandleAudioDecoded(MediaData* aAudio) {}
virtual void HandleVideoDecoded(MediaData* aVideo, TimeStamp aDecodeStart) {}
virtual void HandleEndOfStream() {}
virtual void HandleWaitingForData() {}
virtual void HandleAudioCaptured() {}
virtual RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) = 0;
virtual bool HandleAudioCaptured() { return false; }
virtual RefPtr<ShutdownPromise> HandleShutdown();
virtual void HandleVideoSuspendTimeout() = 0;
@ -278,7 +267,6 @@ protected:
* Transition to other states when decoding metadata is done:
* SHUTDOWN if failing to decode metadata.
* WAIT_FOR_CDM if the media is encrypted and CDM is not available.
* DORMANT if any pending dormant request.
* DECODING_FIRSTFRAME otherwise.
*/
class MediaDecoderStateMachine::DecodeMetadataState
@ -318,12 +306,6 @@ public:
return DECODER_STATE_DECODING_METADATA;
}
bool HandleDormant(bool aDormant) override
{
mPendingDormant = aDormant;
return true;
}
RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
{
MOZ_DIAGNOSTIC_ASSERT(false, "Can't seek while decoding metadata.");
@ -352,18 +334,12 @@ private:
}
MozPromiseRequestHolder<MediaDecoderReader::MetadataPromise> mMetadataRequest;
// True if we need to enter dormant state after reading metadata. Note that
// we can't enter dormant state until reading metadata is done for some
// limitations of the reader.
bool mPendingDormant = false;
};
/**
* Purpose: wait for the CDM to start decoding.
*
* Transition to other states when CDM is ready:
* DORMANT if any pending dormant request.
* DECODING_FIRSTFRAME otherwise.
*/
class MediaDecoderStateMachine::WaitForCDMState
@ -372,10 +348,9 @@ class MediaDecoderStateMachine::WaitForCDMState
public:
explicit WaitForCDMState(Master* aPtr) : StateObject(aPtr) {}
void Enter(bool aPendingDormant)
void Enter()
{
MOZ_ASSERT(!mMaster->mVideoDecodeSuspended);
mPendingDormant = aPendingDormant;
}
void Exit() override
@ -390,9 +365,7 @@ public:
return DECODER_STATE_WAIT_FOR_CDM;
}
bool HandleDormant(bool aDormant) override;
bool HandleCDMProxyReady() override;
void HandleCDMProxyReady() override;
RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
{
@ -414,7 +387,6 @@ public:
}
private:
bool mPendingDormant = false;
SeekJob mPendingSeek;
};
@ -443,8 +415,8 @@ public:
void Exit() override
{
// mPendingSeek is either moved in HandleDormant() or should be rejected
// here before transition to SHUTDOWN.
// mPendingSeek is either moved when exiting dormant or
// should be rejected here before transition to SHUTDOWN.
mPendingSeek.RejectIfExists(__func__);
}
@ -453,8 +425,6 @@ public:
return DECODER_STATE_DORMANT;
}
bool HandleDormant(bool aDormant) override;
RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override;
void HandleVideoSuspendTimeout() override
@ -467,13 +437,7 @@ public:
// Do nothing since we won't resume decoding until exiting dormant.
}
void HandlePlayStateChanged(MediaDecoder::PlayState aPlayState) override
{
if (aPlayState == MediaDecoder::PLAY_STATE_PLAYING) {
// Exit dormant when the user wants to play.
HandleDormant(false);
}
}
void HandlePlayStateChanged(MediaDecoder::PlayState aPlayState) override;
private:
SeekJob mPendingSeek;
@ -483,7 +447,6 @@ private:
* Purpose: decode the 1st audio and video frames to fire the 'loadeddata' event.
*
* Transition to:
* DORMANT if any dormant request.
* SHUTDOWN if any decode error.
* SEEKING if any pending seek and seek is possible.
* DECODING when the 'loadeddata' event is fired.
@ -498,7 +461,7 @@ public:
void Exit() override
{
// mPendingSeek is either moved before transition to SEEKING or DORMANT,
// mPendingSeek is either moved before transition to SEEKING,
// or should be rejected here before transition to SHUTDOWN.
mPendingSeek.RejectIfExists(__func__);
}
@ -508,30 +471,25 @@ public:
return DECODER_STATE_DECODING_FIRSTFRAME;
}
bool HandleAudioDecoded(MediaData* aAudio) override
void HandleAudioDecoded(MediaData* aAudio) override
{
mMaster->Push(aAudio, MediaData::AUDIO_DATA);
MaybeFinishDecodeFirstFrame();
return true;
}
bool HandleVideoDecoded(MediaData* aVideo, TimeStamp aDecodeStart) override
void HandleVideoDecoded(MediaData* aVideo, TimeStamp aDecodeStart) override
{
mMaster->Push(aVideo, MediaData::VIDEO_DATA);
MaybeFinishDecodeFirstFrame();
return true;
}
bool HandleEndOfStream() override
void HandleEndOfStream() override
{
MaybeFinishDecodeFirstFrame();
return true;
}
RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override;
bool HandleDormant(bool aDormant) override;
void HandleVideoSuspendTimeout() override
{
// Do nothing for we need to decode the 1st video frame to get the dimensions.
@ -555,7 +513,7 @@ private:
* Purpose: decode audio/video data for playback.
*
* Transition to:
* DORMANT if any dormant request.
* DORMANT if playback is paused for a while.
* SEEKING if any seek request.
* SHUTDOWN if any decode error.
* BUFFERING if playback can't continue due to lack of decoded data.
@ -610,37 +568,33 @@ public:
return DECODER_STATE_DECODING;
}
bool HandleAudioDecoded(MediaData* aAudio) override
void HandleAudioDecoded(MediaData* aAudio) override
{
mMaster->Push(aAudio, MediaData::AUDIO_DATA);
MaybeStopPrerolling();
return true;
}
bool HandleVideoDecoded(MediaData* aVideo, TimeStamp aDecodeStart) override
void HandleVideoDecoded(MediaData* aVideo, TimeStamp aDecodeStart) override
{
mMaster->Push(aVideo, MediaData::VIDEO_DATA);
MaybeStopPrerolling();
CheckSlowDecoding(aDecodeStart);
return true;
}
RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override;
bool HandleEndOfStream() override;
void HandleEndOfStream() override;
bool HandleWaitingForData() override
void HandleWaitingForData() override
{
MaybeStopPrerolling();
return true;
}
bool HandleAudioCaptured() override
void HandleAudioCaptured() override
{
MaybeStopPrerolling();
// MediaSink is changed. Schedule Step() to check if we can start playback.
mMaster->ScheduleStateMachine();
return true;
}
void HandleVideoSuspendTimeout() override
@ -730,6 +684,20 @@ private:
}
}
void EnterDormant()
{
auto t = mMaster->mMediaSink->IsStarted()
? mMaster->GetClock()
: mMaster->GetMediaTime();
SeekJob seekJob;
seekJob.mTarget = SeekTarget(t, SeekTarget::Accurate,
MediaDecoderEventVisibility::Suppressed);
// SeekJob asserts |mTarget.IsValid() == !mPromise.IsEmpty()| so we
// need to create the promise even it is not used at all.
RefPtr<MediaDecoder::SeekPromise> unused = seekJob.mPromise.Ensure(__func__);
SetState<DormantState>(Move(seekJob));
}
void StartDormantTimer()
{
auto timeout = MediaPrefs::DormantOnPauseTimeout();
@ -738,7 +706,7 @@ private:
return;
} else if (timeout == 0) {
// Enter dormant immediately without scheduling a timer.
HandleDormant(true);
EnterDormant();
return;
}
@ -748,7 +716,7 @@ private:
mDormantTimer.Ensure(target,
[this] () {
mDormantTimer.CompleteRequest();
HandleDormant(true);
EnterDormant();
}, [this] () {
mDormantTimer.CompleteRequest();
});
@ -774,7 +742,6 @@ private:
* Purpose: seek to a particular new playback position.
*
* Transition to:
* DORMANT if any dormant request.
* SEEKING if any new seek request.
* SHUTDOWN if seek failed.
* COMPLETED if the new playback position is the end of the media resource.
@ -871,18 +838,14 @@ public:
return DECODER_STATE_SEEKING;
}
bool HandleDormant(bool aDormant) override;
bool HandleAudioDecoded(MediaData* aAudio) override
void HandleAudioDecoded(MediaData* aAudio) override
{
MOZ_ASSERT(false);
return true;
}
bool HandleVideoDecoded(MediaData* aVideo, TimeStamp aDecodeStart) override
void HandleVideoDecoded(MediaData* aVideo, TimeStamp aDecodeStart) override
{
MOZ_ASSERT(false);
return true;
}
RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override;
@ -952,7 +915,6 @@ private:
* Purpose: stop playback until enough data is decoded to continue playback.
*
* Transition to:
* DORMANT if any dormant request.
* SEEKING if any seek request.
* SHUTDOWN if any decode error.
* COMPLETED when having decoded all audio/video data.
@ -987,25 +949,23 @@ public:
return DECODER_STATE_BUFFERING;
}
bool HandleAudioDecoded(MediaData* aAudio) override
void HandleAudioDecoded(MediaData* aAudio) override
{
// This might be the sample we need to exit buffering.
// Schedule Step() to check it.
mMaster->Push(aAudio, MediaData::AUDIO_DATA);
mMaster->ScheduleStateMachine();
return true;
}
bool HandleVideoDecoded(MediaData* aVideo, TimeStamp aDecodeStart) override
void HandleVideoDecoded(MediaData* aVideo, TimeStamp aDecodeStart) override
{
// This might be the sample we need to exit buffering.
// Schedule Step() to check it.
mMaster->Push(aVideo, MediaData::VIDEO_DATA);
mMaster->ScheduleStateMachine();
return true;
}
bool HandleEndOfStream() override;
void HandleEndOfStream() override;
RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override;
@ -1030,7 +990,6 @@ private:
* Purpose: play all the decoded data and fire the 'ended' event.
*
* Transition to:
* DORMANT if any dormant request.
* SEEKING if any seek request.
*/
class MediaDecoderStateMachine::CompletedState
@ -1102,11 +1061,10 @@ public:
RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override;
bool HandleAudioCaptured() override
void HandleAudioCaptured() override
{
// MediaSink is changed. Schedule Step() to check if we can start playback.
mMaster->ScheduleStateMachine();
return true;
}
void HandleVideoSuspendTimeout() override
@ -1153,11 +1111,6 @@ public:
return DECODER_STATE_SHUTDOWN;
}
bool HandleDormant(bool aDormant) override
{
return true;
}
RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
{
MOZ_DIAGNOSTIC_ASSERT(false, "Can't seek in shutdown state.");
@ -1181,27 +1134,6 @@ public:
}
};
bool
MediaDecoderStateMachine::
StateObject::HandleDormant(bool aDormant)
{
if (!aDormant) {
return true;
}
SeekJob seekJob;
int64_t seekTargetTime = mMaster->mMediaSink->IsStarted()
? mMaster->GetClock() : mMaster->GetMediaTime();
seekJob.mTarget = SeekTarget(seekTargetTime,
SeekTarget::Accurate,
MediaDecoderEventVisibility::Suppressed);
// SeekJob asserts |mTarget.IsValid() == !mPromise.IsEmpty()| so we
// need to create the promise even it is not used at all.
RefPtr<MediaDecoder::SeekPromise> unused = seekJob.mPromise.Ensure(__func__);
SetState<DormantState>(Move(seekJob));
return true;
}
RefPtr<ShutdownPromise>
MediaDecoderStateMachine::
StateObject::HandleShutdown()
@ -1292,6 +1224,8 @@ DecodeMetadataState::OnMetadataRead(MetadataHolder* aMetadata)
mMaster->mInfo = Some(aMetadata->mInfo);
mMaster->mMetadataTags = aMetadata->mTags.forget();
mMaster->mMediaSeekable = Info().mMediaSeekable;
mMaster->mMediaSeekableOnlyInBufferedRanges = Info().mMediaSeekableOnlyInBufferedRanges;
if (Info().mMetadataDuration.isSome()) {
mMaster->RecomputeDuration();
@ -1336,33 +1270,12 @@ DecodeMetadataState::OnMetadataRead(MetadataHolder* aMetadata)
if (waitingForCDM) {
// Metadata parsing was successful but we're still waiting for CDM caps
// to become available so that we can build the correct decryptor/decoder.
SetState<WaitForCDMState>(mPendingDormant);
} else if (mPendingDormant) {
SetState<DormantState>(SeekJob{});
SetState<WaitForCDMState>();
} else {
SetState<DecodingFirstFrameState>(SeekJob{});
}
}
bool
MediaDecoderStateMachine::
WaitForCDMState::HandleDormant(bool aDormant)
{
mPendingDormant = aDormant;
return true;
}
bool
MediaDecoderStateMachine::
DormantState::HandleDormant(bool aDormant)
{
if (!aDormant) {
MOZ_ASSERT(!Info().IsEncrypted() || mMaster->mCDMProxy);
SetState<DecodingFirstFrameState>(Move(mPendingSeek));
}
return true;
}
RefPtr<MediaDecoder::SeekPromise>
MediaDecoderStateMachine::
DormantState::HandleSeek(SeekTarget aTarget)
@ -1374,16 +1287,22 @@ DormantState::HandleSeek(SeekTarget aTarget)
return SetState<SeekingState>(Move(seekJob));
}
bool
void
MediaDecoderStateMachine::
DormantState::HandlePlayStateChanged(MediaDecoder::PlayState aPlayState)
{
if (aPlayState == MediaDecoder::PLAY_STATE_PLAYING) {
// Exit dormant when the user wants to play.
MOZ_ASSERT(!Info().IsEncrypted() || mMaster->mCDMProxy);
SetState<DecodingFirstFrameState>(Move(mPendingSeek));
}
}
void
MediaDecoderStateMachine::
WaitForCDMState::HandleCDMProxyReady()
{
if (mPendingDormant) {
SetState<DormantState>(Move(mPendingSeek));
} else {
SetState<DecodingFirstFrameState>(Move(mPendingSeek));
}
return true;
SetState<DecodingFirstFrameState>(Move(mPendingSeek));
}
void
@ -1437,16 +1356,6 @@ DecodingFirstFrameState::HandleSeek(SeekTarget aTarget)
return SetState<SeekingState>(Move(seekJob));
}
bool
MediaDecoderStateMachine::
DecodingFirstFrameState::HandleDormant(bool aDormant)
{
if (aDormant) {
SetState<DormantState>(Move(mPendingSeek));
}
return true;
}
void
MediaDecoderStateMachine::
DecodingFirstFrameState::MaybeFinishDecodeFirstFrame()
@ -1511,7 +1420,7 @@ DecodingState::HandleSeek(SeekTarget aTarget)
return SetState<SeekingState>(Move(seekJob));
}
bool
void
MediaDecoderStateMachine::
DecodingState::HandleEndOfStream()
{
@ -1520,7 +1429,6 @@ DecodingState::HandleEndOfStream()
} else {
MaybeStopPrerolling();
}
return true;
}
void
@ -1557,26 +1465,6 @@ DecodingState::MaybeStartBuffering()
}
}
bool
MediaDecoderStateMachine::
SeekingState::HandleDormant(bool aDormant)
{
if (!aDormant) {
return true;
}
MOZ_ASSERT(mSeekJob.Exists());
// Because both audio and video decoders are going to be reset in this
// method later, we treat a VideoOnly seek task as a normal Accurate
// seek task so that while it is resumed, both audio and video playback
// are handled.
if (mSeekJob.mTarget.IsVideoOnly()) {
mSeekJob.mTarget.SetType(SeekTarget::Accurate);
mSeekJob.mTarget.SetVideoOnly(false);
}
SetState<DormantState>(Move(mSeekJob));
return true;
}
RefPtr<MediaDecoder::SeekPromise>
MediaDecoderStateMachine::
SeekingState::HandleSeek(SeekTarget aTarget)
@ -1712,7 +1600,7 @@ BufferingState::Step()
SetState<DecodingState>();
}
bool
void
MediaDecoderStateMachine::
BufferingState::HandleEndOfStream()
{
@ -1722,7 +1610,6 @@ BufferingState::HandleEndOfStream()
// Check if we can exit buffering.
mMaster->ScheduleStateMachine();
}
return true;
}
RefPtr<MediaDecoder::SeekPromise>
@ -1776,6 +1663,7 @@ ShutdownState::Enter()
master->mAudioQueueListener.Disconnect();
master->mVideoQueueListener.Disconnect();
master->mMetadataManager.Disconnect();
master->mOnMediaNotSeekable.Disconnect();
// Disconnect canonicals and mirrors before shutting down our task queue.
master->mBuffered.DisconnectIfConnected();
@ -1790,8 +1678,6 @@ ShutdownState::Enter()
master->mPlaybackBytesPerSecond.DisconnectIfConnected();
master->mPlaybackRateReliable.DisconnectIfConnected();
master->mDecoderPosition.DisconnectIfConnected();
master->mMediaSeekable.DisconnectIfConnected();
master->mMediaSeekableOnlyInBufferedRanges.DisconnectIfConnected();
master->mIsVisible.DisconnectIfConnected();
master->mDuration.DisconnectAll();
@ -1863,8 +1749,6 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
INIT_MIRROR(mPlaybackBytesPerSecond, 0.0),
INIT_MIRROR(mPlaybackRateReliable, true),
INIT_MIRROR(mDecoderPosition, 0),
INIT_MIRROR(mMediaSeekable, true),
INIT_MIRROR(mMediaSeekableOnlyInBufferedRanges, false),
INIT_MIRROR(mIsVisible, true),
INIT_CANONICAL(mDuration, NullableTimeUnit()),
INIT_CANONICAL(mIsShutdown, false),
@ -1920,8 +1804,6 @@ MediaDecoderStateMachine::InitializationTask(MediaDecoder* aDecoder)
mPlaybackBytesPerSecond.Connect(aDecoder->CanonicalPlaybackBytesPerSecond());
mPlaybackRateReliable.Connect(aDecoder->CanonicalPlaybackRateReliable());
mDecoderPosition.Connect(aDecoder->CanonicalDecoderPosition());
mMediaSeekable.Connect(aDecoder->CanonicalMediaSeekable());
mMediaSeekableOnlyInBufferedRanges.Connect(aDecoder->CanonicalMediaSeekableOnlyInBufferedRanges());
// Initialize watchers.
mWatchManager.Watch(mBuffered, &MediaDecoderStateMachine::BufferedRangeUpdated);
@ -2301,6 +2183,11 @@ nsresult MediaDecoderStateMachine::Init(MediaDecoder* aDecoder)
mMetadataManager.Connect(mReader->TimedMetadataEvent(), OwnerThread());
mOnMediaNotSeekable = mReader->OnMediaNotSeekable().Connect(
OwnerThread(), [this] () {
mMediaSeekable = false;
});
mMediaSink = CreateMediaSink(mAudioCaptured);
mCDMProxyPromise.Begin(aDecoder->RequestCDMProxy()->Then(
@ -2512,13 +2399,6 @@ void MediaDecoderStateMachine::RecomputeDuration()
mDuration = Some(duration);
}
void
MediaDecoderStateMachine::SetDormant(bool aDormant)
{
MOZ_ASSERT(OnTaskQueue());
mStateObj->HandleDormant(aDormant);
}
RefPtr<ShutdownPromise>
MediaDecoderStateMachine::Shutdown()
{
@ -2968,7 +2848,7 @@ MediaDecoderStateMachine::FinishDecodeFirstFrame()
DECODER_LOG("Media duration %lld, "
"transportSeekable=%d, mediaSeekable=%d",
Duration().ToMicroseconds(), mResource->IsTransportSeekable(), mMediaSeekable.Ref());
Duration().ToMicroseconds(), mResource->IsTransportSeekable(), mMediaSeekable);
// Get potentially updated metadata
mReader->ReadUpdatedMetadata(mInfo.ptr());

Просмотреть файл

@ -281,8 +281,6 @@ private:
// constructor immediately after the task queue is created.
void InitializationTask(MediaDecoder* aDecoder);
void SetDormant(bool aDormant);
void SetAudioCaptured(bool aCaptured);
RefPtr<MediaDecoder::SeekPromise> Seek(SeekTarget aTarget);
@ -736,6 +734,12 @@ private:
// True if video decoding is suspended.
bool mVideoDecodeSuspended;
// True if the media is seekable (i.e. supports random access).
bool mMediaSeekable = true;
// True if the media is seekable only in buffered ranges.
bool mMediaSeekableOnlyInBufferedRanges = false;
// Track enabling video decode suspension via timer
DelayedScheduler mVideoDecodeSuspendTimer;
@ -752,6 +756,7 @@ private:
MediaEventListener mAudioQueueListener;
MediaEventListener mVideoQueueListener;
MediaEventListener mAudibleListener;
MediaEventListener mOnMediaNotSeekable;
MediaEventProducerExc<nsAutoPtr<MediaInfo>,
nsAutoPtr<MetadataTags>,
@ -810,12 +815,6 @@ private:
// Current decoding position in the stream.
Mirror<int64_t> mDecoderPosition;
// True if the media is seekable (i.e. supports random access).
Mirror<bool> mMediaSeekable;
// True if the media is seekable only in buffered ranges.
Mirror<bool> mMediaSeekableOnlyInBufferedRanges;
// IsVisible, mirrored from the media decoder.
Mirror<bool> mIsVisible;

Просмотреть файл

@ -157,29 +157,6 @@ using media::Refcountable;
static Atomic<bool> sInShutdown;
static bool
HostInDomain(const nsCString &aHost, const nsCString &aPattern)
{
int32_t patternOffset = 0;
int32_t hostOffset = 0;
// Act on '*.' wildcard in the left-most position in a domain pattern.
if (aPattern.Length() > 2 && aPattern[0] == '*' && aPattern[1] == '.') {
patternOffset = 2;
// Ignore the lowest level sub-domain for the hostname.
hostOffset = aHost.FindChar('.') + 1;
if (hostOffset <= 1) {
// Reject a match between a wildcard and a TLD or '.foo' form.
return false;
}
}
nsDependentCString hostRoot(aHost, hostOffset);
return hostRoot.EqualsIgnoreCase(aPattern.BeginReading() + patternOffset);
}
static bool
HostIsHttps(nsIURI &docURI)
{
@ -191,58 +168,6 @@ HostIsHttps(nsIURI &docURI)
return isHttps;
}
static bool
HostHasPermission(nsIURI &docURI)
{
nsAdoptingCString hostName;
docURI.GetAsciiHost(hostName); //normalize UTF8 to ASCII equivalent
nsAdoptingCString domainWhiteList =
Preferences::GetCString("media.getusermedia.screensharing.allowed_domains");
domainWhiteList.StripWhitespace();
if (domainWhiteList.IsEmpty() || hostName.IsEmpty()) {
return false;
}
// Get UTF8 to ASCII domain name normalization service
nsresult rv;
nsCOMPtr<nsIIDNService> idnService =
do_GetService("@mozilla.org/network/idn-service;1", &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
uint32_t begin = 0;
uint32_t end = 0;
nsCString domainName;
/*
Test each domain name in the comma separated list
after converting from UTF8 to ASCII. Each domain
must match exactly or have a single leading '*.' wildcard
*/
do {
end = domainWhiteList.FindChar(',', begin);
if (end == (uint32_t)-1) {
// Last or only domain name in the comma separated list
end = domainWhiteList.Length();
}
rv = idnService->ConvertUTF8toACE(Substring(domainWhiteList, begin, end - begin),
domainName);
if (NS_SUCCEEDED(rv)) {
if (HostInDomain(hostName, domainName)) {
return true;
}
} else {
NS_WARNING("Failed to convert UTF-8 host to ASCII");
}
begin = end + 1;
} while (end < domainWhiteList.Length());
return false;
}
/**
* This class is an implementation of MediaStreamListener. This is used
* to Start() and Stop() the underlying MediaEngineSource when MediaStreams
@ -2218,8 +2143,7 @@ if (privileged) {
!Preferences::GetBool("media.getusermedia.screensharing.allow_on_old_platforms",
false) && !IsVistaOrLater()) ||
#endif
(!privileged && !HostIsHttps(*docURI)) ||
(!isChrome && !HostHasPermission(*docURI))) {
(!privileged && !HostIsHttps(*docURI))) {
RefPtr<MediaStreamError> error =
new MediaStreamError(aWindow,
NS_LITERAL_STRING("NotAllowedError"));

Просмотреть файл

@ -122,6 +122,7 @@ private:
#endif
#ifdef XP_WIN
DECL_MEDIA_PREF("media.wmf.enabled", PDMWMFEnabled, bool, true);
DECL_MEDIA_PREF("media.wmf.skip-blacklist", PDMWMFSkipBlacklist, bool, false);
DECL_MEDIA_PREF("media.decoder-doctor.wmf-disabled-is-failure", DecoderDoctorWMFDisabledIsFailure, bool, false);
DECL_MEDIA_PREF("media.wmf.vp9.enabled", PDMWMFVP9DecoderEnabled, bool, true);
DECL_MEDIA_PREF("media.wmf.decoder.thread-count", PDMWMFThreadCount, int32_t, -1);

Просмотреть файл

@ -34,9 +34,6 @@ public:
// Notify is duration is known to this MediaResource.
virtual void SetInfinite(bool aInfinite) {}
// Notify if seeking is supported by this MediaResource.
virtual void SetMediaSeekable(bool aMediaSeekable) {}
// Notify that a network error is encountered.
virtual void NotifyNetworkError() {}

Просмотреть файл

@ -15,6 +15,9 @@
#include "mozilla/dom/UnionTypes.h"
#include "mozilla/Telemetry.h"
#include "GMPCDMProxy.h"
#ifdef MOZ_WIDGET_ANDROID
#include "mozilla/MediaDrmCDMProxy.h"
#endif
#include "mozilla/EMEUtils.h"
#include "nsContentUtils.h"
#include "nsIScriptObjectPrincipal.h"
@ -325,6 +328,28 @@ private:
WeakPtr<MediaKeys> mMediaKeys;
};
already_AddRefed<CDMProxy>
MediaKeys::CreateCDMProxy()
{
RefPtr<CDMProxy> proxy;
#ifdef MOZ_WIDGET_ANDROID
if (IsWidevineKeySystem(mKeySystem)) {
proxy = new MediaDrmCDMProxy(this,
mKeySystem,
mConfig.mDistinctiveIdentifier == MediaKeysRequirement::Required,
mConfig.mPersistentState == MediaKeysRequirement::Required);
} else
#endif
{
proxy = new GMPCDMProxy(this,
mKeySystem,
new MediaKeysGMPCrashHelper(this),
mConfig.mDistinctiveIdentifier == MediaKeysRequirement::Required,
mConfig.mPersistentState == MediaKeysRequirement::Required);
}
return proxy.forget();
}
already_AddRefed<DetailedPromise>
MediaKeys::Init(ErrorResult& aRv)
{
@ -334,11 +359,7 @@ MediaKeys::Init(ErrorResult& aRv)
return nullptr;
}
mProxy = new GMPCDMProxy(this,
mKeySystem,
new MediaKeysGMPCrashHelper(this),
mConfig.mDistinctiveIdentifier == MediaKeysRequirement::Required,
mConfig.mPersistentState == MediaKeysRequirement::Required);
mProxy = CreateCDMProxy();
// Determine principal (at creation time) of the MediaKeys object.
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(GetParentObject());

Просмотреть файл

@ -133,7 +133,9 @@ public:
private:
bool IsInPrivateBrowsing();
// Instantiate CDMProxy instance.
// It could be MediaDrmCDMProxy (Widevine on Fennec) or GMPCDMProxy (the rest).
already_AddRefed<CDMProxy> CreateCDMProxy();
// Removes promise from mPromises, and returns it.
already_AddRefed<DetailedPromise> RetrievePromise(PromiseId aId);

Просмотреть файл

@ -199,12 +199,11 @@ MediaDrmProxySupport::MediaDrmProxySupport(const nsAString& aKeySystem)
: mKeySystem(aKeySystem), mDestroyed(false)
{
mJavaCallbacks = MediaDrmProxy::NativeMediaDrmProxyCallbacks::New();
// TODO: Bug 1306196 will check the pref to determine if it is oop case.
// Follow the pref flag PDMAndroidRemoteCodecEnabled returned to determine
// it is crossing process CDM or not.
mBridgeProxy =
MediaDrmProxy::Create(mKeySystem,
mJavaCallbacks);
mJavaCallbacks,
MediaPrefs::PDMAndroidRemoteCodecEnabled());
}
MediaDrmProxySupport::~MediaDrmProxySupport()

Просмотреть файл

@ -24,6 +24,10 @@ using namespace mozilla::layers;
namespace media {
// Minimum update frequency is 1/120th of a second, i.e. half the
// duration of a 60-fps frame.
static const int64_t MIN_UPDATE_INTERVAL_US = 1000000 / (60 * 2);
VideoSink::VideoSink(AbstractThread* aThread,
MediaSink* aAudioSink,
MediaQueue<MediaData>& aVideoQueue,
@ -441,8 +445,9 @@ VideoSink::UpdateRenderedVideoFrames()
}
int64_t nextFrameTime = frames[1]->mTime;
int64_t delta = std::max<int64_t>((nextFrameTime - clockTime), MIN_UPDATE_INTERVAL_US);
TimeStamp target = nowTime + TimeDuration::FromMicroseconds(
(nextFrameTime - clockTime) / mAudioSink->GetPlaybackParams().mPlaybackRate);
delta / mAudioSink->GetPlaybackParams().mPlaybackRate);
RefPtr<VideoSink> self = this;
mUpdateScheduler.Ensure(target, [self] () {

Просмотреть файл

@ -18,6 +18,7 @@
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/layers/LayersTypes.h"
#include "MediaInfo.h"
#include "MediaPrefs.h"
#include "mozilla/Logging.h"
#include "nsWindowsHelpers.h"
#include "gfx2DGlue.h"
@ -66,7 +67,7 @@ const CLSID CLSID_WebmMfVpxDec =
};
namespace mozilla {
LayersBackend
GetCompositorBackendType(layers::KnowsCompositor* aKnowsCompositor)
{
@ -180,8 +181,8 @@ FindDXVABlacklistedDLL(StaticAutoPtr<D3DDLLBlacklistingCache>& aDLLBlacklistingC
ClearOnShutdown(&aDLLBlacklistingCache);
}
if (aBlacklist.IsEmpty()) {
// Empty blacklist -> No blacklisting.
if (aBlacklist.IsEmpty() || MediaPrefs::PDMWMFSkipBlacklist()) {
// Empty blacklist, or "media.wmf.skip-blacklist"=true -> No blacklisting.
aDLLBlacklistingCache->mBlacklistPref.SetLength(0);
aDLLBlacklistingCache->mBlacklistedDLL.SetLength(0);
return aDLLBlacklistingCache->mBlacklistedDLL;

Двоичные данные
dom/media/test/bug1301226-odd.wav Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1 @@
Cache-Control: no-store

Двоичные данные
dom/media/test/bug1301226.wav Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1 @@
Cache-Control: no-store

Просмотреть файл

@ -165,6 +165,10 @@ var gPlayTests = [
{ name:"wavedata_alaw.wav", type:"audio/x-wav", duration:1.0 },
// uLaw compressed wave file
{ name:"wavedata_ulaw.wav", type:"audio/x-wav", duration:1.0 },
// Data length 0xFFFFFFFF
{ name:"bug1301226.wav", type:"audio/x-wav", duration:0.003673 },
// Data length 0xFFFFFFFF and odd chunk lengths.
{ name:"bug1301226-odd.wav", type:"audio/x-wav", duration:0.003673 },
// Ogg stream without eof marker
{ name:"bug461281.ogg", type:"application/ogg", duration:2.208 },

Просмотреть файл

@ -391,6 +391,10 @@ support-files =
bug883173.vtt
bug1066943.webm
bug1066943.webm^headers^
bug1301226.wav
bug1301226.wav^headers^
bug1301226-odd.wav
bug1301226-odd.wav^headers^
can_play_type_dash.js
can_play_type_ogg.js
can_play_type_wave.js

Просмотреть файл

@ -11,10 +11,6 @@
bug: "1211656"
});
var mustFailWith = (msg, reason, f) =>
f().then(() => ok(false, msg + " must fail"),
e => is(e.name, reason, msg + " must fail: " + e.message));
var pushPrefs = (...p) => new Promise(r => SpecialPowers.pushPrefEnv({set: p}, r));
/**
@ -63,15 +59,9 @@
}
];
return Promise.resolve()
// Screensharing must work even without "mochi.test," in allowed_domains
.then(() => pushPrefs(["media.getusermedia.screensharing.allowed_domains",
"mozilla.github.io,*.bugzilla.mozilla.org"]))
.then(() => mustFailWith("Screensharing if absent in allowed_domains",
"NotAllowedError",
() => navigator.mediaDevices.getUserMedia({
video: videoConstraints[0], fake: false
})))
.then(() => pushPrefs(["media.getusermedia.screensharing.allowed_domains",
"mozilla.github.io,mochi.test,*.bugzilla.mozilla.org"]))
.then(() => getUserMedia(constraints).then(stream => {
var playback = new LocalMediaStreamPlayback(testVideo, stream);
return playback.playMediaWithDeprecatedStreamStop(false);

Просмотреть файл

@ -133,8 +133,11 @@ WAVTrackDemuxer::Init()
}
break;
} else {
mOffset += aChunkSize; // Skip other irrelevant chunks.
}
if (mOffset & 1) {
// Wave files are 2-byte aligned so we need to round up
mOffset += (aChunkSize + 1) & ~1; // Skip other irrelevant chunks.
mOffset += 1;
}
mHeaderParser.Reset();
}

Просмотреть файл

@ -6,9 +6,6 @@
DIRS += ['interfaces']
if CONFIG['MOZ_B2G_RIL']:
XPCSHELL_TESTS_MANIFESTS += ['tests/unit_stats/xpcshell.ini']
MOCHITEST_CHROME_MANIFESTS += ['tests/chrome.ini']
MOCHITEST_MANIFESTS += ['tests/mochitest.ini']

Просмотреть файл

@ -31,9 +31,6 @@ XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
MOCHITEST_MANIFESTS += ['tests/mochitest.ini']
if CONFIG['MOZ_B2G_RIL']:
MOCHITEST_MANIFESTS += ['tests/mochitest-ril.ini']
if CONFIG['MOZ_TIME_MANAGER']:
MOCHITEST_MANIFESTS += ['tests/mochitest-time.ini']

Просмотреть файл

@ -34,11 +34,6 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['MOZ_SECUREELEMENT']:
XPCSHELL_TESTS_MANIFESTS += [
'tests/unit/xpcshell.ini'
]
if CONFIG['MOZ_B2G_RIL']:
EXTRA_COMPONENTS += [
'gonk/UiccConnector.js',
'gonk/UiccConnector.manifest',
]
include('/ipc/chromium/chromium-config.mozbuild')

Просмотреть файл

@ -1,4 +1,5 @@
[DEFAULT]
skip-if = (os == 'linux' && debug && bits == 32) # bug 1311599
support-files =
head.js
file_priming-top.html

Просмотреть файл

@ -21,9 +21,6 @@
#include "AudioManager.h"
#include "nsIObserverService.h"
#ifdef MOZ_B2G_RIL
#include "nsIRadioInterfaceLayer.h"
#endif
#include "nsISettingsService.h"
#include "nsPrintfCString.h"
@ -694,9 +691,6 @@ AudioManager::AudioManager()
, mA2dpSwitchDone(true)
#endif
, mObserver(new HeadphoneSwitchObserver())
#ifdef MOZ_B2G_RIL
, mMuteCallToRIL(false)
#endif
{
for (uint32_t idx = 0; idx < MOZ_ARRAY_LENGTH(kAudioDeviceInfos); ++idx) {
mAudioDeviceTableIdMaps.Put(kAudioDeviceInfos[idx].value, idx);
@ -754,13 +748,6 @@ AudioManager::AudioManager()
NS_WARNING("Failed to add audio-channel-process-changed observer!");
}
#ifdef MOZ_B2G_RIL
char value[PROPERTY_VALUE_MAX];
property_get("ro.moz.mute.call.to_ril", value, "false");
if (!strcmp(value, "true")) {
mMuteCallToRIL = true;
}
#endif
}
AudioManager::~AudioManager() {
@ -815,13 +802,6 @@ AudioManager::GetInstance()
NS_IMETHODIMP
AudioManager::GetMicrophoneMuted(bool* aMicrophoneMuted)
{
#ifdef MOZ_B2G_RIL
if (mMuteCallToRIL) {
// Simply return cached mIsMicMuted if mute call go via RIL.
*aMicrophoneMuted = mIsMicMuted;
return NS_OK;
}
#endif
if (AudioSystem::isMicrophoneMuted(aMicrophoneMuted)) {
return NS_ERROR_FAILURE;
@ -833,15 +813,6 @@ NS_IMETHODIMP
AudioManager::SetMicrophoneMuted(bool aMicrophoneMuted)
{
if (!AudioSystem::muteMicrophone(aMicrophoneMuted)) {
#ifdef MOZ_B2G_RIL
if (mMuteCallToRIL) {
// Extra mute request to RIL for specific platform.
nsCOMPtr<nsIRadioInterfaceLayer> ril = do_GetService("@mozilla.org/ril;1");
NS_ENSURE_TRUE(ril, NS_ERROR_FAILURE);
ril->SetMicrophoneMuted(aMicrophoneMuted);
mIsMicMuted = aMicrophoneMuted;
}
#endif
return NS_OK;
}
return NS_ERROR_FAILURE;

Просмотреть файл

@ -141,11 +141,6 @@ protected:
private:
nsAutoPtr<mozilla::hal::SwitchObserver> mObserver;
#ifdef MOZ_B2G_RIL
bool mMuteCallToRIL;
// mIsMicMuted is only used for toggling mute call to RIL.
bool mIsMicMuted;
#endif
void HandleBluetoothStatusChanged(nsISupports* aSubject,
const char* aTopic,

Просмотреть файл

@ -39,18 +39,6 @@
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/SettingChangeNotificationBinding.h"
#ifdef MOZ_B2G_RIL
#include "mozstumbler/MozStumbler.h"
#include "nsIIccInfo.h"
#include "nsIMobileConnectionInfo.h"
#include "nsIMobileConnectionService.h"
#include "nsIMobileCellInfo.h"
#include "nsIMobileNetworkInfo.h"
#include "nsIRadioInterfaceLayer.h"
#include "nsIIccService.h"
#include "nsIDataCallManager.h"
#endif
#ifdef AGPS_TYPE_INVALID
#define AGPS_HAVE_DUAL_APN
#endif
@ -70,14 +58,7 @@ using namespace mozilla::dom;
static const int kDefaultPeriod = 1000; // ms
static bool gDebug_isLoggingEnabled = false;
static bool gDebug_isGPSLocationIgnored = false;
#ifdef MOZ_B2G_RIL
static const char* kNetworkConnStateChangedTopic = "network-connection-state-changed";
#endif
static const char* kMozSettingsChangedTopic = "mozsettings-changed";
#ifdef MOZ_B2G_RIL
static const char* kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces";
static const char* kSettingRilDefaultServiceId = "ril.data.defaultServiceId";
#endif
// Both of these settings can be toggled in the Gaia Developer settings screen.
static const char* kSettingDebugEnabled = "geolocation.debugging.enabled";
static const char* kSettingDebugGpsIgnored = "geolocation.debugging.gps-locations-ignored";
@ -93,11 +74,6 @@ NS_IMPL_ISUPPORTS(GonkGPSGeolocationProvider,
/* static */ GonkGPSGeolocationProvider* GonkGPSGeolocationProvider::sSingleton = nullptr;
GpsCallbacks GonkGPSGeolocationProvider::mCallbacks;
#ifdef MOZ_B2G_RIL
AGpsCallbacks GonkGPSGeolocationProvider::mAGPSCallbacks;
AGpsRilCallbacks GonkGPSGeolocationProvider::mAGPSRILCallbacks;
#endif // MOZ_B2G_RIL
void
GonkGPSGeolocationProvider::LocationCallback(GpsLocation* location)
@ -156,9 +132,6 @@ GonkGPSGeolocationProvider::LocationCallback(GpsLocation* location)
RefPtr<UpdateLocationEvent> event = new UpdateLocationEvent(somewhere);
NS_DispatchToMainThread(event);
#ifdef MOZ_B2G_RIL
MozStumble(somewhere);
#endif
}
class NotifyObserversGPSTask final : public Runnable
@ -280,10 +253,6 @@ GonkGPSGeolocationProvider::SetCapabilitiesCallback(uint32_t capabilities)
GonkGPSGeolocationProvider::GetSingleton();
provider->mSupportsScheduling = mCapabilities & GPS_CAPABILITY_SCHEDULING;
#ifdef MOZ_B2G_RIL
provider->mSupportsMSB = mCapabilities & GPS_CAPABILITY_MSB;
provider->mSupportsMSA = mCapabilities & GPS_CAPABILITY_MSA;
#endif
provider->mSupportsSingleShot = mCapabilities & GPS_CAPABILITY_SINGLE_SHOT;
#ifdef GPS_CAPABILITY_ON_DEMAND_TIME
provider->mSupportsTimeInjection = mCapabilities & GPS_CAPABILITY_ON_DEMAND_TIME;
@ -332,90 +301,9 @@ GonkGPSGeolocationProvider::RequestUtcTimeCallback()
{
}
#ifdef MOZ_B2G_RIL
void
GonkGPSGeolocationProvider::AGPSStatusCallback(AGpsStatus* status)
{
MOZ_ASSERT(status);
class AGPSStatusEvent : public Runnable {
public:
AGPSStatusEvent(AGpsStatusValue aStatus)
: mStatus(aStatus)
{}
NS_IMETHOD Run() override {
RefPtr<GonkGPSGeolocationProvider> provider =
GonkGPSGeolocationProvider::GetSingleton();
switch (mStatus) {
case GPS_REQUEST_AGPS_DATA_CONN:
provider->RequestDataConnection();
break;
case GPS_RELEASE_AGPS_DATA_CONN:
provider->ReleaseDataConnection();
break;
}
return NS_OK;
}
private:
AGpsStatusValue mStatus;
};
NS_DispatchToMainThread(new AGPSStatusEvent(status->status));
}
void
GonkGPSGeolocationProvider::AGPSRILSetIDCallback(uint32_t flags)
{
class RequestSetIDEvent : public Runnable {
public:
RequestSetIDEvent(uint32_t flags)
: mFlags(flags)
{}
NS_IMETHOD Run() override {
RefPtr<GonkGPSGeolocationProvider> provider =
GonkGPSGeolocationProvider::GetSingleton();
provider->RequestSetID(mFlags);
return NS_OK;
}
private:
uint32_t mFlags;
};
NS_DispatchToMainThread(new RequestSetIDEvent(flags));
}
void
GonkGPSGeolocationProvider::AGPSRILRefLocCallback(uint32_t flags)
{
class RequestRefLocEvent : public Runnable {
public:
RequestRefLocEvent()
{}
NS_IMETHOD Run() override {
RefPtr<GonkGPSGeolocationProvider> provider =
GonkGPSGeolocationProvider::GetSingleton();
provider->SetReferenceLocation();
return NS_OK;
}
};
if (flags & AGPS_RIL_REQUEST_REFLOC_CELLID) {
NS_DispatchToMainThread(new RequestRefLocEvent());
}
}
#endif // MOZ_B2G_RIL
GonkGPSGeolocationProvider::GonkGPSGeolocationProvider()
: mStarted(false)
, mSupportsScheduling(false)
#ifdef MOZ_B2G_RIL
, mSupportsMSB(false)
, mSupportsMSA(false)
, mRilDataServiceId(0)
, mNumberOfRilServices(1)
, mObservingNetworkConnStateChange(false)
#endif
, mObservingSettingsChange(false)
, mSupportsSingleShot(false)
, mSupportsTimeInjection(false)
@ -464,66 +352,6 @@ GonkGPSGeolocationProvider::GetGPSInterface()
return result;
}
#ifdef MOZ_B2G_RIL
int32_t
GonkGPSGeolocationProvider::GetDataConnectionState()
{
if (!mRadioInterface) {
return nsINetworkInfo::NETWORK_STATE_UNKNOWN;
}
int32_t state;
mRadioInterface->GetDataCallStateByType(
nsINetworkInfo::NETWORK_TYPE_MOBILE_SUPL, &state);
return state;
}
void
GonkGPSGeolocationProvider::SetAGpsDataConn(nsAString& aApn)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mAGpsInterface);
bool hasUpdateNetworkAvailability = false;
if (mAGpsRilInterface &&
mAGpsRilInterface->size >= sizeof(AGpsRilInterface) &&
mAGpsRilInterface->update_network_availability) {
hasUpdateNetworkAvailability = true;
}
int32_t connectionState = GetDataConnectionState();
NS_ConvertUTF16toUTF8 apn(aApn);
if (connectionState == nsINetworkInfo::NETWORK_STATE_CONNECTED) {
// The definition of availability is
// 1. The device is connected to the home network
// 2. The device is connected to a foreign network and data
// roaming is enabled
// RIL turns on/off data connection automatically when the data
// roaming setting changes.
if (hasUpdateNetworkAvailability) {
mAGpsRilInterface->update_network_availability(true, apn.get());
}
#ifdef AGPS_HAVE_DUAL_APN
mAGpsInterface->data_conn_open(AGPS_TYPE_SUPL,
apn.get(),
AGPS_APN_BEARER_IPV4);
#else
mAGpsInterface->data_conn_open(apn.get());
#endif
} else if (connectionState == nsINetworkInfo::NETWORK_STATE_DISCONNECTED) {
if (hasUpdateNetworkAvailability) {
mAGpsRilInterface->update_network_availability(false, apn.get());
}
#ifdef AGPS_HAVE_DUAL_APN
mAGpsInterface->data_conn_closed(AGPS_TYPE_SUPL);
#else
mAGpsInterface->data_conn_closed();
#endif
}
}
#endif // MOZ_B2G_RIL
void
GonkGPSGeolocationProvider::RequestSettingValue(const char* aKey)
{
@ -548,199 +376,6 @@ GonkGPSGeolocationProvider::RequestSettingValue(const char* aKey)
}
}
#ifdef MOZ_B2G_RIL
void
GonkGPSGeolocationProvider::RequestDataConnection()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mRadioInterface) {
return;
}
if (GetDataConnectionState() == nsINetworkInfo::NETWORK_STATE_CONNECTED) {
// Connection is already established, we don't need to setup again.
// We just get supl APN and make AGPS data connection state updated.
RequestSettingValue("ril.supl.apn");
} else {
mRadioInterface->SetupDataCallByType(nsINetworkInfo::NETWORK_TYPE_MOBILE_SUPL);
}
}
void
GonkGPSGeolocationProvider::ReleaseDataConnection()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mRadioInterface) {
return;
}
mRadioInterface->DeactivateDataCallByType(nsINetworkInfo::NETWORK_TYPE_MOBILE_SUPL);
}
void
GonkGPSGeolocationProvider::RequestSetID(uint32_t flags)
{
MOZ_ASSERT(NS_IsMainThread());
if (!mRadioInterface ||
!mAGpsInterface) {
return;
}
AGpsSetIDType type = AGPS_SETID_TYPE_NONE;
nsCOMPtr<nsIIccService> iccService =
do_GetService(ICC_SERVICE_CONTRACTID);
NS_ENSURE_TRUE_VOID(iccService);
nsCOMPtr<nsIIcc> icc;
iccService->GetIccByServiceId(mRilDataServiceId, getter_AddRefs(icc));
NS_ENSURE_TRUE_VOID(icc);
nsAutoString id;
if (flags & AGPS_RIL_REQUEST_SETID_IMSI) {
type = AGPS_SETID_TYPE_IMSI;
icc->GetImsi(id);
}
if (flags & AGPS_RIL_REQUEST_SETID_MSISDN) {
nsCOMPtr<nsIIccInfo> iccInfo;
icc->GetIccInfo(getter_AddRefs(iccInfo));
if (iccInfo) {
nsCOMPtr<nsIGsmIccInfo> gsmIccInfo = do_QueryInterface(iccInfo);
if (gsmIccInfo) {
type = AGPS_SETID_TYPE_MSISDN;
gsmIccInfo->GetMsisdn(id);
}
}
}
NS_ConvertUTF16toUTF8 idBytes(id);
mAGpsRilInterface->set_set_id(type, idBytes.get());
}
namespace {
int
ConvertToGpsRefLocationType(const nsAString& aConnectionType)
{
const char* GSM_TYPES[] = { "gsm", "gprs", "edge" };
const char* UMTS_TYPES[] = { "umts", "hspda", "hsupa", "hspa", "hspa+" };
for (auto type: GSM_TYPES) {
if (aConnectionType.EqualsASCII(type)) {
return AGPS_REF_LOCATION_TYPE_GSM_CELLID;
}
}
for (auto type: UMTS_TYPES) {
if (aConnectionType.EqualsASCII(type)) {
return AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
}
}
if (gDebug_isLoggingEnabled) {
DBG("geo: Unsupported connection type %s\n",
NS_ConvertUTF16toUTF8(aConnectionType).get());
}
return AGPS_REF_LOCATION_TYPE_GSM_CELLID;
}
} // namespace
void
GonkGPSGeolocationProvider::SetReferenceLocation()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mRadioInterface ||
!mAGpsRilInterface) {
return;
}
AGpsRefLocation location;
nsCOMPtr<nsIMobileConnectionService> service =
do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID);
if (!service) {
NS_WARNING("Cannot get MobileConnectionService");
return;
}
nsCOMPtr<nsIMobileConnection> connection;
service->GetItemByServiceId(mRilDataServiceId, getter_AddRefs(connection));
NS_ENSURE_TRUE_VOID(connection);
nsCOMPtr<nsIMobileConnectionInfo> voice;
connection->GetVoice(getter_AddRefs(voice));
if (voice) {
nsAutoString connectionType;
nsresult rv = voice->GetType(connectionType);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
location.type = ConvertToGpsRefLocationType(connectionType);
nsCOMPtr<nsIMobileNetworkInfo> networkInfo;
voice->GetNetwork(getter_AddRefs(networkInfo));
if (networkInfo) {
nsresult result;
nsAutoString mcc, mnc;
networkInfo->GetMcc(mcc);
networkInfo->GetMnc(mnc);
location.u.cellID.mcc = mcc.ToInteger(&result);
if (result != NS_OK) {
NS_WARNING("Cannot parse mcc to integer");
location.u.cellID.mcc = 0;
}
location.u.cellID.mnc = mnc.ToInteger(&result);
if (result != NS_OK) {
NS_WARNING("Cannot parse mnc to integer");
location.u.cellID.mnc = 0;
}
} else {
NS_WARNING("Cannot get mobile network info.");
location.u.cellID.mcc = 0;
location.u.cellID.mnc = 0;
}
nsCOMPtr<nsIMobileCellInfo> cell;
voice->GetCell(getter_AddRefs(cell));
if (cell) {
int32_t lac;
int64_t cid;
cell->GetGsmLocationAreaCode(&lac);
// The valid range of LAC is 0x0 to 0xffff which is defined in
// hardware/ril/include/telephony/ril.h
if (lac >= 0x0 && lac <= 0xffff) {
location.u.cellID.lac = lac;
}
cell->GetGsmCellId(&cid);
// The valid range of cell id is 0x0 to 0xffffffff which is defined in
// hardware/ril/include/telephony/ril.h
if (cid >= 0x0 && cid <= 0xffffffff) {
location.u.cellID.cid = cid;
}
} else {
NS_WARNING("Cannot get mobile gell info.");
location.u.cellID.lac = -1;
location.u.cellID.cid = -1;
}
} else {
NS_WARNING("Cannot get mobile connection info.");
return;
}
mAGpsRilInterface->set_ref_location(&location, sizeof(location));
}
#endif // MOZ_B2G_RIL
void
GonkGPSGeolocationProvider::InjectLocation(double latitude,
double longitude,
@ -784,34 +419,12 @@ GonkGPSGeolocationProvider::Init()
mCallbacks.request_utc_time_cb = RequestUtcTimeCallback;
#endif
#ifdef MOZ_B2G_RIL
mAGPSCallbacks.status_cb = AGPSStatusCallback;
mAGPSCallbacks.create_thread_cb = CreateThreadCallback;
mAGPSRILCallbacks.request_setid = AGPSRILSetIDCallback;
mAGPSRILCallbacks.request_refloc = AGPSRILRefLocCallback;
mAGPSRILCallbacks.create_thread_cb = CreateThreadCallback;
#endif
}
if (mGpsInterface->init(&mCallbacks) != 0) {
return;
}
#ifdef MOZ_B2G_RIL
mAGpsInterface =
static_cast<const AGpsInterface*>(mGpsInterface->get_extension(AGPS_INTERFACE));
if (mAGpsInterface) {
mAGpsInterface->init(&mAGPSCallbacks);
}
mAGpsRilInterface =
static_cast<const AGpsRilInterface*>(mGpsInterface->get_extension(AGPS_RIL_INTERFACE));
if (mAGpsRilInterface) {
mAGpsRilInterface->init(&mAGPSRILCallbacks);
}
#endif
NS_DispatchToMainThread(NewRunnableMethod(this, &GonkGPSGeolocationProvider::StartGPS));
}
@ -823,24 +436,8 @@ GonkGPSGeolocationProvider::StartGPS()
int32_t update = Preferences::GetInt("geo.default.update", kDefaultPeriod);
#ifdef MOZ_B2G_RIL
if (mSupportsMSA || mSupportsMSB) {
SetupAGPS();
}
#endif
int positionMode = GPS_POSITION_MODE_STANDALONE;
#ifdef MOZ_B2G_RIL
bool singleShot = false;
// XXX: If we know this is a single shot request, use MSA can be faster.
if (singleShot && mSupportsMSA) {
positionMode = GPS_POSITION_MODE_MS_ASSISTED;
} else if (mSupportsMSB) {
positionMode = GPS_POSITION_MODE_MS_BASED;
}
#endif
if (!mSupportsScheduling) {
update = kDefaultPeriod;
}
@ -856,43 +453,6 @@ GonkGPSGeolocationProvider::StartGPS()
mGpsInterface->start();
}
#ifdef MOZ_B2G_RIL
void
GonkGPSGeolocationProvider::SetupAGPS()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mAGpsInterface);
const nsAdoptingCString& suplServer = Preferences::GetCString("geo.gps.supl_server");
int32_t suplPort = Preferences::GetInt("geo.gps.supl_port", -1);
if (!suplServer.IsEmpty() && suplPort > 0) {
mAGpsInterface->set_server(AGPS_TYPE_SUPL, suplServer.get(), suplPort);
} else {
NS_WARNING("Cannot get SUPL server settings");
return;
}
// Request RIL date service ID for correct RadioInterface object first due to
// multi-SIM case needs it to handle AGPS related stuffs. For single SIM, 0
// will be returned as default RIL data service ID.
RequestSettingValue(kSettingRilDefaultServiceId);
}
void
GonkGPSGeolocationProvider::UpdateRadioInterface()
{
nsCOMPtr<nsIRadioInterfaceLayer> ril = do_GetService("@mozilla.org/ril;1");
NS_ENSURE_TRUE_VOID(ril);
ril->GetRadioInterface(mRilDataServiceId, getter_AddRefs(mRadioInterface));
}
bool
GonkGPSGeolocationProvider::IsValidRilServiceId(uint32_t aServiceId)
{
return aServiceId < mNumberOfRilServices;
}
#endif // MOZ_B2G_RIL
NS_IMPL_ISUPPORTS(GonkGPSGeolocationProvider::NetworkLocationUpdate,
nsIGeolocationUpdate)
@ -1013,9 +573,6 @@ GonkGPSGeolocationProvider::Startup()
}
mStarted = true;
#ifdef MOZ_B2G_RIL
mNumberOfRilServices = Preferences::GetUint(kPrefRilNumRadioInterfaces, 1);
#endif
return NS_OK;
}
@ -1046,14 +603,6 @@ GonkGPSGeolocationProvider::Shutdown()
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (obs) {
nsresult rv;
#ifdef MOZ_B2G_RIL
rv = obs->RemoveObserver(this, kNetworkConnStateChangedTopic);
if (NS_FAILED(rv)) {
NS_WARNING("geo: Gonk GPS network state RemoveObserver failed");
} else {
mObservingNetworkConnStateChange = false;
}
#endif
rv = obs->RemoveObserver(this, kMozSettingsChangedTopic);
if (NS_FAILED(rv)) {
NS_WARNING("geo: Gonk GPS mozsettings RemoveObserver failed");
@ -1115,59 +664,6 @@ GonkGPSGeolocationProvider::Observe(nsISupports* aSubject,
{
MOZ_ASSERT(NS_IsMainThread());
#ifdef MOZ_B2G_RIL
if (!strcmp(aTopic, kNetworkConnStateChangedTopic)) {
nsCOMPtr<nsINetworkInfo> info = do_QueryInterface(aSubject);
if (!info) {
return NS_OK;
}
nsCOMPtr<nsIRilNetworkInfo> rilInfo = do_QueryInterface(aSubject);
if (mAGpsRilInterface && mAGpsRilInterface->update_network_state) {
int32_t state;
int32_t type;
info->GetState(&state);
info->GetType(&type);
bool connected = (state == nsINetworkInfo::NETWORK_STATE_CONNECTED);
bool roaming = false;
int gpsNetworkType = ConvertToGpsNetworkType(type);
if (gpsNetworkType >= 0) {
if (rilInfo) {
do {
nsCOMPtr<nsIMobileConnectionService> service =
do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID);
if (!service) {
break;
}
nsCOMPtr<nsIMobileConnection> connection;
service->GetItemByServiceId(mRilDataServiceId, getter_AddRefs(connection));
if (!connection) {
break;
}
nsCOMPtr<nsIMobileConnectionInfo> voice;
connection->GetVoice(getter_AddRefs(voice));
if (voice) {
voice->GetRoaming(&roaming);
}
} while (0);
}
mAGpsRilInterface->update_network_state(
connected,
gpsNetworkType,
roaming,
/* extra_info = */ nullptr);
}
}
// No data connection
if (!rilInfo) {
return NS_OK;
}
RequestSettingValue("ril.supl.apn");
}
#endif
if (!strcmp(aTopic, kMozSettingsChangedTopic)) {
// Read changed setting value
RootedDictionary<SettingChangeNotification> setting(RootingCx());
@ -1189,18 +685,6 @@ GonkGPSGeolocationProvider::Observe(nsISupports* aSubject,
setting.mValue.isBoolean() ? setting.mValue.toBoolean() : false;
return NS_OK;
}
#ifdef MOZ_B2G_RIL
else if (setting.mKey.EqualsASCII(kSettingRilDefaultServiceId)) {
if (!setting.mValue.isNumber() ||
!IsValidRilServiceId(setting.mValue.toNumber())) {
return NS_ERROR_UNEXPECTED;
}
mRilDataServiceId = setting.mValue.toNumber();
UpdateRadioInterface();
return NS_OK;
}
#endif
}
return NS_OK;
@ -1212,50 +696,6 @@ NS_IMETHODIMP
GonkGPSGeolocationProvider::Handle(const nsAString& aName,
JS::Handle<JS::Value> aResult)
{
#ifdef MOZ_B2G_RIL
if (aName.EqualsLiteral("ril.supl.apn")) {
// When we get the APN, we attempt to call data_call_open of AGPS.
if (aResult.isString()) {
JSContext *cx = nsContentUtils::GetCurrentJSContext();
NS_ENSURE_TRUE(cx, NS_OK);
// NB: No need to enter a compartment to read the contents of a string.
nsAutoJSString apn;
if (!apn.init(cx, aResult.toString())) {
return NS_ERROR_FAILURE;
}
if (!apn.IsEmpty()) {
SetAGpsDataConn(apn);
}
}
} else if (aName.EqualsASCII(kSettingRilDefaultServiceId)) {
uint32_t id = 0;
JSContext *cx = nsContentUtils::GetCurrentJSContext();
NS_ENSURE_TRUE(cx, NS_OK);
if (!JS::ToUint32(cx, aResult, &id)) {
return NS_ERROR_FAILURE;
}
if (!IsValidRilServiceId(id)) {
return NS_ERROR_UNEXPECTED;
}
mRilDataServiceId = id;
UpdateRadioInterface();
MOZ_ASSERT(!mObservingNetworkConnStateChange);
// Now we know which service ID to deal with, observe necessary topic then
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE(obs, NS_OK);
if (NS_FAILED(obs->AddObserver(this, kNetworkConnStateChangedTopic, false))) {
NS_WARNING("Failed to add network state changed observer!");
} else {
mObservingNetworkConnStateChange = true;
}
}
#endif // MOZ_B2G_RIL
return NS_OK;
}

Просмотреть файл

@ -22,9 +22,6 @@
#include "nsIGeolocationProvider.h"
#include "nsIObserver.h"
#include "nsIDOMGeoPosition.h"
#ifdef MOZ_B2G_RIL
#include "nsIRadioInterfaceLayer.h"
#endif
#include "nsISettingsService.h"
class nsIThread;
@ -64,34 +61,14 @@ private:
static void ReleaseWakelockCallback();
static pthread_t CreateThreadCallback(const char* name, void (*start)(void*), void* arg);
static void RequestUtcTimeCallback();
#ifdef MOZ_B2G_RIL
static void AGPSStatusCallback(AGpsStatus* status);
static void AGPSRILSetIDCallback(uint32_t flags);
static void AGPSRILRefLocCallback(uint32_t flags);
#endif
static GpsCallbacks mCallbacks;
#ifdef MOZ_B2G_RIL
static AGpsCallbacks mAGPSCallbacks;
static AGpsRilCallbacks mAGPSRILCallbacks;
#endif
void Init();
void StartGPS();
void ShutdownGPS();
void InjectLocation(double latitude, double longitude, float accuracy);
void RequestSettingValue(const char* aKey);
#ifdef MOZ_B2G_RIL
void UpdateRadioInterface();
bool IsValidRilServiceId(uint32_t aServiceId);
void SetupAGPS();
int32_t GetDataConnectionState();
void SetAGpsDataConn(nsAString& aApn);
void RequestDataConnection();
void ReleaseDataConnection();
void RequestSetID(uint32_t flags);
void SetReferenceLocation();
#endif
const GpsInterface* GetGPSInterface();
@ -100,26 +77,11 @@ private:
bool mStarted;
bool mSupportsScheduling;
#ifdef MOZ_B2G_RIL
bool mSupportsMSB;
bool mSupportsMSA;
uint32_t mRilDataServiceId;
// mNumberOfRilServices indicates how many SIM slots supported on device, and
// RadioInterfaceLayer.js takes responsibility to set up the corresponding
// preference value.
uint32_t mNumberOfRilServices;
bool mObservingNetworkConnStateChange;
#endif
bool mObservingSettingsChange;
bool mSupportsSingleShot;
bool mSupportsTimeInjection;
const GpsInterface* mGpsInterface;
#ifdef MOZ_B2G_RIL
const AGpsInterface* mAGpsInterface;
const AGpsRilInterface* mAGpsRilInterface;
nsCOMPtr<nsIRadioInterface> mRadioInterface;
#endif
nsCOMPtr<nsIGeolocationUpdate> mLocationCallback;
nsCOMPtr<nsIThread> mInitThread;
nsCOMPtr<nsIGeolocationProvider> mNetworkLocationProvider;

Просмотреть файл

@ -28,9 +28,6 @@
#include "TimeZoneSettingObserver.h"
#include "AudioManager.h"
#include "mozilla/dom/ScriptSettings.h"
#ifdef MOZ_B2G_RIL
#include "mozilla/ipc/Ril.h"
#endif
#include "mozilla/ipc/KeyStore.h"
#include "nsIObserverService.h"
#include "nsServiceManagerUtils.h"
@ -115,10 +112,6 @@ SystemWorkerManager::Shutdown()
ShutdownAutoMounter();
#ifdef MOZ_B2G_RIL
RilWorker::Shutdown();
#endif
nsCOMPtr<nsIWifi> wifi(do_QueryInterface(mWifiWorker));
if (wifi) {
wifi->Shutdown();
@ -184,22 +177,7 @@ SystemWorkerManager::RegisterRilWorker(unsigned int aClientId,
JS::Handle<JS::Value> aWorker,
JSContext *aCx)
{
#ifndef MOZ_B2G_RIL
return NS_ERROR_NOT_IMPLEMENTED;
#else
NS_ENSURE_TRUE(aWorker.isObject(), NS_ERROR_UNEXPECTED);
JSAutoCompartment ac(aCx, &aWorker.toObject());
WorkerCrossThreadDispatcher *wctd =
GetWorkerCrossThreadDispatcher(aCx, aWorker);
if (!wctd) {
NS_WARNING("Failed to GetWorkerCrossThreadDispatcher for ril");
return NS_ERROR_FAILURE;
}
return RilWorker::Register(aClientId, wctd);
#endif // MOZ_B2G_RIL
}
nsresult

Просмотреть файл

@ -89,43 +89,6 @@ EXTRA_JS_MODULES += [
'systemlibs.js',
]
if CONFIG['MOZ_B2G_RIL']:
EXPORTS += [
'mozstumbler/MozStumbler.h',
]
UNIFIED_SOURCES += [
'mozstumbler/MozStumbler.cpp',
'mozstumbler/StumblerLogging.cpp',
'mozstumbler/UploadStumbleRunnable.cpp',
'mozstumbler/WriteStumbleOnThread.cpp'
]
XPIDL_SOURCES += [
'nsIDataCallInterfaceService.idl',
'nsIDataCallManager.idl',
'nsIGonkDataCallInterfaceService.idl',
'nsIRadioInterfaceLayer.idl',
]
EXTRA_COMPONENTS += [
'DataCallManager.js',
'DataCallManager.manifest',
'RILSystemMessengerHelper.js',
'RILSystemMessengerHelper.manifest',
]
EXTRA_JS_MODULES += [
'ril_consts.js',
'ril_worker.js',
'ril_worker_buf_object.js',
'ril_worker_telephony_request_queue.js',
'RILSystemMessenger.jsm',
]
if not CONFIG['DISABLE_MOZ_RIL_GEOLOC']:
EXTRA_COMPONENTS += [
'DataCallInterfaceService.js',
'DataCallInterfaceService.manifest',
'RadioInterfaceLayer.js',
'RadioInterfaceLayer.manifest',
]
include('/ipc/chromium/chromium-config.mozbuild')
DEFINES['HAVE_ANDROID_OS'] = True

Просмотреть файл

@ -565,7 +565,7 @@ var interfaceNamesInGlobalScope =
// IMPORTANT: Do not change this list without review from a DOM peer!
"HTMLVideoElement",
// IMPORTANT: Do not change this list without review from a DOM peer!
"IdleDeadline",
{name: "IdleDeadline", nightly: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
"IDBCursor",
// IMPORTANT: Do not change this list without review from a DOM peer!

Просмотреть файл

@ -25,9 +25,10 @@ dictionary KeyframeEffectOptions : AnimationEffectTimingProperties {
// the first argument since we cannot convert a mixin into a union type
// automatically.
[Func="nsDocument::IsWebAnimationsEnabled",
Constructor((Element or CSSPseudoElement)? target,
object? keyframes,
optional (unrestricted double or KeyframeEffectOptions) options)]
Constructor ((Element or CSSPseudoElement)? target,
object? keyframes,
optional (unrestricted double or KeyframeEffectOptions) options),
Constructor (KeyframeEffectReadOnly source)]
interface KeyframeEffectReadOnly : AnimationEffectReadOnly {
// Bug 1241783: As with the constructor, we use (Element or CSSPseudoElement)?
// for the type of |target| instead of Animatable?
@ -36,9 +37,6 @@ interface KeyframeEffectReadOnly : AnimationEffectReadOnly {
readonly attribute CompositeOperation composite;
readonly attribute DOMString spacing;
// Not yet implemented:
// KeyframeEffect clone();
// We use object instead of ComputedKeyframe so that we can put the
// property-value pairs on the object.
[Throws] sequence<object> getKeyframes();
@ -66,7 +64,8 @@ partial interface KeyframeEffectReadOnly {
[Func="nsDocument::IsWebAnimationsEnabled",
Constructor ((Element or CSSPseudoElement)? target,
object? keyframes,
optional (unrestricted double or KeyframeEffectOptions) options)]
optional (unrestricted double or KeyframeEffectOptions) options),
Constructor (KeyframeEffectReadOnly source)]
interface KeyframeEffect : KeyframeEffectReadOnly {
inherit attribute (Element or CSSPseudoElement)? target;
inherit attribute IterationCompositeOperation iterationComposite;

Просмотреть файл

@ -77,6 +77,7 @@ class Animation;
class AnimationData;
class AsyncCanvasRenderer;
class AsyncPanZoomController;
class BasicLayerManager;
class ClientLayerManager;
class Layer;
class LayerMetricsWrapper;
@ -196,6 +197,9 @@ public:
virtual ClientLayerManager* AsClientLayerManager()
{ return nullptr; }
virtual BasicLayerManager* AsBasicLayerManager()
{ return nullptr; }
/**
* Returns true if this LayerManager is owned by an nsIWidget,
* and is used for drawing into the widget.

Просмотреть файл

@ -74,6 +74,8 @@ protected:
virtual ~BasicLayerManager();
public:
BasicLayerManager* AsBasicLayerManager() override { return this; }
/**
* Set the default target context that will be used when BeginTransaction
* is called. This can only be called outside a transaction.

Просмотреть файл

@ -42,6 +42,7 @@
#include "mozilla/layers/Effects.h" // for Effect, EffectChain, etc
#include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
#include "mozilla/layers/LayersTypes.h" // for etc
#include "mozilla/widget/CompositorWidget.h" // for WidgetRenderingContext
#include "ipc/CompositorBench.h" // for CompositorBench
#include "ipc/ShadowLayerUtils.h"
#include "mozilla/mozalloc.h" // for operator new, etc
@ -911,11 +912,18 @@ LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion, const nsIntRegi
mLastFrameMissedHWC = !!composer2D;
}
mozilla::widget::WidgetRenderingContext widgetContext;
#if defined(XP_MACOSX)
widgetContext.mLayerManager = this;
#elif defined(MOZ_WIDGET_ANDROID)
widgetContext.mCompositor = GetCompositor();
#endif
{
PROFILER_LABEL("LayerManagerComposite", "PreRender",
js::ProfileEntry::Category::GRAPHICS);
if (!mCompositor->GetWidget()->PreRender(this)) {
if (!mCompositor->GetWidget()->PreRender(&widgetContext)) {
return;
}
}
@ -946,13 +954,13 @@ LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion, const nsIntRegi
}
if (actualBounds.IsEmpty()) {
mCompositor->GetWidget()->PostRender(this);
mCompositor->GetWidget()->PostRender(&widgetContext);
return;
}
// Allow widget to render a custom background.
mCompositor->GetWidget()->DrawWindowUnderlay(
this, LayoutDeviceIntRect::FromUnknownRect(actualBounds));
&widgetContext, LayoutDeviceIntRect::FromUnknownRect(actualBounds));
RefPtr<CompositingRenderTarget> previousTarget;
if (haveLayerEffects) {
@ -980,7 +988,7 @@ LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion, const nsIntRegi
// Allow widget to render a custom foreground.
mCompositor->GetWidget()->DrawWindowOverlay(
this, LayoutDeviceIntRect::FromUnknownRect(actualBounds));
&widgetContext, LayoutDeviceIntRect::FromUnknownRect(actualBounds));
// Debugging
RenderDebugOverlay(actualBounds);
@ -999,7 +1007,7 @@ LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion, const nsIntRegi
composer2D->Render(mCompositor->GetWidget()->RealWidget());
}
mCompositor->GetWidget()->PostRender(this);
mCompositor->GetWidget()->PostRender(&widgetContext);
RecordFrame();
}

Просмотреть файл

@ -11,13 +11,10 @@ DIRS += [
'testshell',
]
if CONFIG['MOZ_B2G_RIL']:
DIRS += ['ril']
if CONFIG['MOZ_ENABLE_DBUS']:
DIRS += ['dbus']
if CONFIG['MOZ_B2G_RIL'] or CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
DIRS += ['unixfd', 'unixsocket']
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':

Просмотреть файл

@ -549,7 +549,7 @@ RegisterAllocator::getMoveGroupAfter(LInstruction* ins)
void
RegisterAllocator::dumpInstructions()
{
#ifdef DEBUG
#ifdef JS_JITSPEW
fprintf(stderr, "Instructions:\n");
for (size_t blockIndex = 0; blockIndex < graph.numBlocks(); blockIndex++) {
@ -610,5 +610,5 @@ RegisterAllocator::dumpInstructions()
}
}
fprintf(stderr, "\n");
#endif // DEBUG
#endif // JS_JITSPEW
}

Просмотреть файл

@ -8229,8 +8229,8 @@ nsLayoutUtils::DoLogTestDataForPaint(LayerManager* aManager,
const std::string& aKey,
const std::string& aValue)
{
if (aManager->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
static_cast<ClientLayerManager*>(aManager)->LogTestDataForCurrentPaint(aScrollId, aKey, aValue);
if (ClientLayerManager* mgr = aManager->AsClientLayerManager()) {
mgr->LogTestDataForCurrentPaint(aScrollId, aKey, aValue);
}
}

Просмотреть файл

@ -456,7 +456,7 @@ public:
nscoord GetCrossSize() const { return mCrossSize; }
nscoord GetCrossPosition() const { return mCrossPosn; }
nscoord ResolvedAscent() const {
nscoord ResolvedAscent(bool aUseFirstBaseline) const {
if (mAscent == ReflowOutput::ASK_FOR_BASELINE) {
// XXXdholbert We should probably be using the *container's* writing-mode
// here, instead of the item's -- though it doesn't much matter right
@ -465,8 +465,13 @@ public:
// will matter more (& can be expanded/tested) once we officially support
// logical directions & vertical writing-modes in flexbox, in bug 1079155
// or a dependency.
// Use GetFirstLineBaseline(), or just GetBaseline() if that fails.
if (!nsLayoutUtils::GetFirstLineBaseline(mWM, mFrame, &mAscent)) {
// Use GetFirstLineBaseline() or GetLastLineBaseline() as appropriate,
// or just GetLogicalBaseline() if that fails.
bool found = aUseFirstBaseline ?
nsLayoutUtils::GetFirstLineBaseline(mWM, mFrame, &mAscent) :
nsLayoutUtils::GetLastLineBaseline(mWM, mFrame, &mAscent);
if (!found) {
mAscent = mFrame->GetLogicalBaseline(mWM);
}
}
@ -492,7 +497,8 @@ public:
// from, so that it can look up the appropriate components from mMargin.)
nscoord GetBaselineOffsetFromOuterCrossEdge(
AxisEdgeType aEdge,
const FlexboxAxisTracker& aAxisTracker) const;
const FlexboxAxisTracker& aAxisTracker,
bool aUseFirstLineBaseline) const;
float GetShareOfWeightSoFar() const { return mShareOfWeightSoFar; }
@ -826,7 +832,8 @@ public:
mTotalInnerHypotheticalMainSize(0),
mTotalOuterHypotheticalMainSize(0),
mLineCrossSize(0),
mBaselineOffset(nscoord_MIN)
mFirstBaselineOffset(nscoord_MIN),
mLastBaselineOffset(nscoord_MIN)
{}
// Returns the sum of our FlexItems' outer hypothetical main sizes.
@ -925,8 +932,22 @@ public:
*
* If there are no baseline-aligned FlexItems, returns nscoord_MIN.
*/
nscoord GetBaselineOffset() const {
return mBaselineOffset;
nscoord GetFirstBaselineOffset() const {
return mFirstBaselineOffset;
}
/**
* Returns the offset within this line where any last baseline-aligned
* FlexItems should place their baseline. Opposite the case of the first
* baseline offset, this represents a distance from the line's cross-end
* edge (since last baseline-aligned items are flush to the cross-end edge).
* If we're internally reversing the axes, this instead represents the
* distance from the line's cross-start edge.
*
* If there are no last baseline-aligned FlexItems, returns nscoord_MIN.
*/
nscoord GetLastBaselineOffset() const {
return mLastBaselineOffset;
}
// Runs the "Resolving Flexible Lengths" algorithm from section 9.7 of the
@ -965,7 +986,8 @@ private:
nscoord mTotalInnerHypotheticalMainSize;
nscoord mTotalOuterHypotheticalMainSize;
nscoord mLineCrossSize;
nscoord mBaselineOffset;
nscoord mFirstBaselineOffset;
nscoord mLastBaselineOffset;
};
// Information about a strut left behind by a FlexItem that's been collapsed
@ -1891,19 +1913,20 @@ FlexItem::FlexItem(ReflowInput& aFlexItemReflowInput,
}
#endif // DEBUG
// If the flex item's inline axis is the same as the cross axis, then
// 'align-self:baseline' is identical to 'flex-start'. If that's the case, we
// just directly convert our align-self value here, so that we don't have to
// handle this with special cases elsewhere.
// Moreover: for the time being (until we support writing-modes),
// all inline axes are horizontal -- so we can just check if the cross axis
// is horizontal.
// FIXME: Once we support writing-mode (vertical text), this
// IsCrossAxisHorizontal check won't be sufficient anymore -- we'll actually
// need to compare our inline axis vs. the cross axis.
if (mAlignSelf == NS_STYLE_ALIGN_BASELINE &&
aAxisTracker.IsCrossAxisHorizontal()) {
mAlignSelf = NS_STYLE_ALIGN_FLEX_START;
// Map align-self 'baseline' value to 'start' when baseline alignment
// is not possible because the FlexItem's writing mode is orthogonal to
// the main axis of the container. If that's the case, we just directly
// convert our align-self value here, so that we don't have to handle this
// with special cases elsewhere.
// We are treating this case as one where it is appropriate to use the
// fallback values defined at https://www.w3.org/TR/css-align-3/#baseline
if (aAxisTracker.IsRowOriented() ==
aAxisTracker.GetWritingMode().IsOrthogonalTo(mWM)) {
if (mAlignSelf == NS_STYLE_ALIGN_BASELINE) {
mAlignSelf = NS_STYLE_ALIGN_FLEX_START;
} else if (mAlignSelf == NS_STYLE_ALIGN_LAST_BASELINE) {
mAlignSelf = NS_STYLE_ALIGN_FLEX_END;
}
}
}
@ -1976,7 +1999,8 @@ FlexItem::CheckForMinSizeAuto(const ReflowInput& aFlexItemReflowInput,
nscoord
FlexItem::GetBaselineOffsetFromOuterCrossEdge(
AxisEdgeType aEdge,
const FlexboxAxisTracker& aAxisTracker) const
const FlexboxAxisTracker& aAxisTracker,
bool aUseFirstLineBaseline) const
{
// NOTE: Currently, 'mAscent' (taken from reflow) is an inherently vertical
// measurement -- it's the distance from the border-top edge of this FlexItem
@ -1990,7 +2014,8 @@ FlexItem::GetBaselineOffsetFromOuterCrossEdge(
AxisOrientationType crossAxis = aAxisTracker.GetCrossAxis();
mozilla::Side sideToMeasureFrom = kAxisOrientationToSidesMap[crossAxis][aEdge];
nscoord marginTopToBaseline = ResolvedAscent() + mMargin.top;
nscoord marginTopToBaseline = ResolvedAscent(aUseFirstLineBaseline) +
mMargin.top;
if (sideToMeasureFrom == eSideTop) {
// Measuring from top (normal case): the distance from the margin-box top
@ -3089,15 +3114,19 @@ SingleLineCrossAxisPositionTracker::
void
FlexLine::ComputeCrossSizeAndBaseline(const FlexboxAxisTracker& aAxisTracker)
{
nscoord crossStartToFurthestBaseline = nscoord_MIN;
nscoord crossEndToFurthestBaseline = nscoord_MIN;
nscoord crossStartToFurthestFirstBaseline = nscoord_MIN;
nscoord crossEndToFurthestFirstBaseline = nscoord_MIN;
nscoord crossStartToFurthestLastBaseline = nscoord_MIN;
nscoord crossEndToFurthestLastBaseline = nscoord_MIN;
nscoord largestOuterCrossSize = 0;
for (const FlexItem* item = mItems.getFirst(); item; item = item->getNext()) {
nscoord curOuterCrossSize =
item->GetOuterCrossSize(aAxisTracker.GetCrossAxis());
if (item->GetAlignSelf() == NS_STYLE_ALIGN_BASELINE &&
if ((item->GetAlignSelf() == NS_STYLE_ALIGN_BASELINE ||
item->GetAlignSelf() == NS_STYLE_ALIGN_LAST_BASELINE) &&
item->GetNumAutoMarginsInAxis(aAxisTracker.GetCrossAxis()) == 0) {
const bool useFirst = (item->GetAlignSelf() == NS_STYLE_ALIGN_BASELINE);
// FIXME: Once we support "writing-mode", we'll have to do baseline
// alignment in vertical flex containers here (w/ horizontal cross-axes).
@ -3129,16 +3158,24 @@ FlexLine::ComputeCrossSizeAndBaseline(const FlexboxAxisTracker& aAxisTracker)
nscoord crossStartToBaseline =
item->GetBaselineOffsetFromOuterCrossEdge(eAxisEdge_Start,
aAxisTracker);
aAxisTracker,
useFirst);
nscoord crossEndToBaseline = curOuterCrossSize - crossStartToBaseline;
// Now, update our "largest" values for these (across all the flex items
// in this flex line), so we can use them in computing the line's cross
// size below:
crossStartToFurthestBaseline = std::max(crossStartToFurthestBaseline,
crossStartToBaseline);
crossEndToFurthestBaseline = std::max(crossEndToFurthestBaseline,
crossEndToBaseline);
if (useFirst) {
crossStartToFurthestFirstBaseline =
std::max(crossStartToFurthestFirstBaseline, crossStartToBaseline);
crossEndToFurthestFirstBaseline =
std::max(crossEndToFurthestFirstBaseline, crossEndToBaseline);
} else {
crossStartToFurthestLastBaseline =
std::max(crossStartToFurthestLastBaseline, crossStartToBaseline);
crossEndToFurthestLastBaseline =
std::max(crossEndToFurthestLastBaseline, crossEndToBaseline);
}
} else {
largestOuterCrossSize = std::max(largestOuterCrossSize, curOuterCrossSize);
}
@ -3148,17 +3185,24 @@ FlexLine::ComputeCrossSizeAndBaseline(const FlexboxAxisTracker& aAxisTracker)
// end, depending on whether we've flipped the axes) to the furthest
// item-baseline. The item(s) with that baseline will be exactly aligned with
// the line's edge.
mBaselineOffset = aAxisTracker.AreAxesInternallyReversed() ?
crossEndToFurthestBaseline : crossStartToFurthestBaseline;
mFirstBaselineOffset = aAxisTracker.AreAxesInternallyReversed() ?
crossEndToFurthestFirstBaseline : crossStartToFurthestFirstBaseline;
mLastBaselineOffset = aAxisTracker.AreAxesInternallyReversed() ?
crossStartToFurthestLastBaseline : crossEndToFurthestLastBaseline;
// The line's cross-size is the larger of:
// (a) [largest cross-start-to-baseline + largest baseline-to-cross-end] of
// all baseline-aligned items with no cross-axis auto margins...
// and
// (b) largest cross-size of all other children.
mLineCrossSize = std::max(crossStartToFurthestBaseline +
crossEndToFurthestBaseline,
largestOuterCrossSize);
// (b) [largest cross-start-to-baseline + largest baseline-to-cross-end] of
// all last baseline-aligned items with no cross-axis auto margins...
// and
// (c) largest cross-size of all other children.
mLineCrossSize = std::max(
std::max(crossStartToFurthestFirstBaseline + crossEndToFurthestFirstBaseline,
crossStartToFurthestLastBaseline + crossEndToFurthestLastBaseline),
largestOuterCrossSize);
}
void
@ -3288,8 +3332,7 @@ SingleLineCrossAxisPositionTracker::
switch (alignSelf) {
case NS_STYLE_ALIGN_SELF_START:
case NS_STYLE_ALIGN_SELF_END:
case NS_STYLE_ALIGN_LAST_BASELINE:
NS_WARNING("NYI: align-items/align-self:left/right/self-start/self-end/last baseline");
NS_WARNING("NYI: align-items/align-self:left/right/self-start/self-end");
MOZ_FALLTHROUGH;
case NS_STYLE_ALIGN_FLEX_START:
// No space to skip over -- we're done.
@ -3302,19 +3345,25 @@ SingleLineCrossAxisPositionTracker::
mPosition +=
(aLine.GetLineCrossSize() - aItem.GetOuterCrossSize(mAxis)) / 2;
break;
case NS_STYLE_ALIGN_BASELINE: {
case NS_STYLE_ALIGN_BASELINE:
case NS_STYLE_ALIGN_LAST_BASELINE: {
const bool useFirst = (alignSelf == NS_STYLE_ALIGN_BASELINE);
// Normally, baseline-aligned items are collectively aligned with the
// line's cross-start edge; however, if our cross axis is (internally)
// reversed, we instead align them with the cross-end edge.
// A similar logic holds for last baseline-aligned items, but in reverse.
AxisEdgeType baselineAlignEdge =
aAxisTracker.AreAxesInternallyReversed() ?
aAxisTracker.AreAxesInternallyReversed() == useFirst ?
eAxisEdge_End : eAxisEdge_Start;
nscoord itemBaselineOffset =
aItem.GetBaselineOffsetFromOuterCrossEdge(baselineAlignEdge,
aAxisTracker);
aAxisTracker,
useFirst);
nscoord lineBaselineOffset = aLine.GetBaselineOffset();
nscoord lineBaselineOffset = useFirst ? aLine.GetFirstBaselineOffset()
: aLine.GetLastBaselineOffset();
NS_ASSERTION(lineBaselineOffset >= itemBaselineOffset,
"failed at finding largest baseline offset");
@ -3323,7 +3372,7 @@ SingleLineCrossAxisPositionTracker::
// to get the item's baseline to hit the line's baseline offset:
nscoord baselineDiff = lineBaselineOffset - itemBaselineOffset;
if (aAxisTracker.AreAxesInternallyReversed()) {
if (aAxisTracker.AreAxesInternallyReversed() == useFirst) {
// Advance to align item w/ line's flex-end edge (as in FLEX_END case):
mPosition += aLine.GetLineCrossSize() - aItem.GetOuterCrossSize(mAxis);
// ...and step *back* by the baseline adjustment:
@ -4276,7 +4325,7 @@ nsFlexContainerFrame::DoFlexLayout(nsPresContext* aPresContext,
// measured from):
nscoord flexContainerAscent;
if (!aAxisTracker.AreAxesInternallyReversed()) {
nscoord firstLineBaselineOffset = lines.getFirst()->GetBaselineOffset();
nscoord firstLineBaselineOffset = lines.getFirst()->GetFirstBaselineOffset();
if (firstLineBaselineOffset == nscoord_MIN) {
// No baseline-aligned items in line. Use sentinel value to prompt us to
// get baseline from the first FlexItem after we've reflowed it.
@ -4313,7 +4362,7 @@ nsFlexContainerFrame::DoFlexLayout(nsPresContext* aPresContext,
// at the cross-end edge of that line, which the line's baseline offset is
// measured from):
if (aAxisTracker.AreAxesInternallyReversed()) {
nscoord lastLineBaselineOffset = lines.getLast()->GetBaselineOffset();
nscoord lastLineBaselineOffset = lines.getLast()->GetFirstBaselineOffset();
if (lastLineBaselineOffset == nscoord_MIN) {
// No baseline-aligned items in line. Use sentinel value to prompt us to
// get baseline from the last FlexItem after we've reflowed it.
@ -4412,10 +4461,11 @@ nsFlexContainerFrame::DoFlexLayout(nsPresContext* aPresContext,
// If this is our first item and we haven't established a baseline for
// the container yet (i.e. if we don't have 'align-self: baseline' on any
// children), then use this child's baseline as the container's baseline.
// children), then use this child's first baseline as the container's
// baseline.
if (item == firstItem &&
flexContainerAscent == nscoord_MIN) {
flexContainerAscent = itemNormalBPos + item->ResolvedAscent();
flexContainerAscent = itemNormalBPos + item->ResolvedAscent(true);
}
}
}

Просмотреть файл

@ -61,5 +61,13 @@
<i>ital<br/>ic</i>
</table>
</div>
<div class="flexbox">
<div class="lime">blk_1line</div
><div class="yellow">blk<br/>2lines</div
><div class="orange"><span class="super">super</span></div
><div class="pink"><span class="sub">sub</span></div
><div class="aqua big">big<br/>text<br/>3lines</div
><div class="tan"><i>ital<br/>ic</i></div>
</div>
</body>
</html>

Просмотреть файл

@ -17,10 +17,15 @@
<style>
.flexbox {
display: flex;
align-items: baseline;
border: 1px dashed blue;
font: 14px sans-serif;
}
.base {
align-items: baseline;
}
.lastbase {
align-items: last baseline;
}
.big {
height: 100px;
@ -45,7 +50,15 @@
</style>
</head>
<body>
<div class="flexbox">
<div class="flexbox base">
<div class="lime">blk_1line</div>
<div class="yellow">blk<br/>2lines</div>
<div class="orange"><span class="super">super</span></div>
<div class="pink"><span class="sub">sub</span></div>
<div class="aqua big">big<br/>text<br/>3lines</div>
<i class="tan">ital<br/>ic</i>
</div>
<div class="flexbox lastbase">
<div class="lime">blk_1line</div>
<div class="yellow">blk<br/>2lines</div>
<div class="orange"><span class="super">super</span></div>

Просмотреть файл

@ -19,11 +19,16 @@
<style>
.flexbox {
display: flex;
align-items: baseline;
flex-wrap: wrap-reverse;
border: 1px dashed blue;
font: 14px sans-serif;
}
.base {
align-items: baseline;
}
.lastbase {
align-items: last baseline;
}
.big {
height: 100px;
@ -48,7 +53,15 @@
</style>
</head>
<body>
<div class="flexbox">
<div class="flexbox base">
<div class="lime">blk_1line</div>
<div class="yellow">blk<br/>2lines</div>
<div class="orange"><span class="super">super</span></div>
<div class="pink"><span class="sub">sub</span></div>
<div class="aqua big">big<br/>text<br/>3lines</div>
<i class="tan">ital<br/>ic</i>
</div>
<div class="flexbox lastbase">
<div class="lime">blk_1line</div>
<div class="yellow">blk<br/>2lines</div>
<div class="orange"><span class="super">super</span></div>

Просмотреть файл

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!-- Reference case for behavior of the 'baseline' value for align-items and
align-self when tested against content with an orthogonal writing-mode.
-->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>CSS Reftest Reference</title>
<link rel="author" title="Brad Werth" href="mailto:bwerth@mozilla.com"/>
<style>
.container {
display: flex;
border: 1px dashed blue;
font: 14px sans-serif;
height: 50px;
}
.ortho { writing-mode: vertical-rl;
width: 17px;
height: 40px;
float: left; }
.offset { margin-top: 10px;
margin-bottom: 3px; }
.start { align-self: flex-start; }
.end { align-self: flex-end; }
.lime { background: lime; }
.yellow { background: yellow; }
.orange { background: orange; }
.pink { background: pink; }
</style>
</head>
<body>
<div class="container">
<div class="lime ortho start">ortho</div
><div class="yellow offset start">one line</div
><div class="orange offset start">two<br/>lines</div
><div class="pink offset start">offset</div>
</div>
<div class="container">
<div class="lime ortho end">ortho</div
><div class="yellow offset end">one line</div
><div class="orange offset end">two<br/>lines</div
><div class="pink offset end">offset</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!-- Testcase for behavior of the 'baseline' value for align-items (and
align-self, implicitly). This test baseline-aligns various types of
content against content that is exempt from alignment due to an
orthognal writing-mode.
-->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>CSS Test: Baseline alignment of block flex items with 'baseline' value for 'align-items' / 'align-self' against non-parallel writing-modes.</title>
<link rel="author" title="Brad Werth" href="mailto:bwerth@mozilla.com"/>
<link rel="help" href="http://www.w3.org/TR/css-flexbox-1/#baseline-participation"/>
<link rel="match" href="flexbox-align-self-baseline-horiz-006-ref.xhtml"/>
<style>
.container {
display: flex;
border: 1px dashed blue;
font: 14px sans-serif;
height: 50px;
}
.base { align-items: baseline; }
.lastbase { align-items: last baseline; }
.ortho { writing-mode: vertical-rl;
width: 17px;
height: 40px; }
.offset { margin-top: 10px;
margin-bottom: 3px; }
.lime { background: lime; }
.yellow { background: yellow; }
.orange { background: orange; }
.pink { background: pink; }
</style>
</head>
<body>
<div class="container base">
<div class="lime ortho">ortho</div>
<div class="yellow">one line</div>
<div class="orange">two<br/>lines</div>
<div class="pink offset">offset</div>
</div>
<div class="container lastbase">
<div class="lime ortho">ortho</div>
<div class="yellow">one line</div>
<div class="orange">two<br/>lines</div>
<div class="pink offset">offset</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!-- Reference case for behavior of 'baseline' and 'last baseline' values
for align-items and align-self.
-->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>CSS Reftest Reference</title>
<link rel="author" title="Brad Werth" href="mailto:bwerth@mozilla.com"/>
<style>
.container {
display: flex;
border: 1px dashed blue;
font: 14px sans-serif;
height: 50px;
}
.start { align-self: flex-start; }
.end { align-self: flex-end; }
.offset { margin-top: 10px;
margin-bottom: 3px; }
.lime { background: lime; }
.yellow { background: yellow; }
.orange { background: orange; }
.pink { background: pink; }
</style>
</head>
<body>
<div class="container">
<div class="lime offset start">one line (first)</div
><div class="yellow offset end">one line (last)</div
><div class="orange offset end">two<br/>lines and offset (last)</div
><div class="pink offset start">offset (first)</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!-- Testcase for behavior of 'baseline' and 'last baseline' values
for align-items (and align-self, implicitly). This test confirms
non-interference between the 'baseline' and 'last baseline' items.
-->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>CSS Test: Baseline alignment of block flex items with 'baseline' and 'last-baseline' values for 'align-self' against each other.</title>
<link rel="author" title="Brad Werth" href="mailto:bwerth@mozilla.com"/>
<link rel="help" href="http://www.w3.org/TR/css-flexbox-1/#baseline-participation"/>
<link rel="match" href="flexbox-align-self-baseline-horiz-007-ref.xhtml"/>
<style>
.container {
display: flex;
border: 1px dashed blue;
font: 14px sans-serif;
height: 50px;
}
.base { align-self: baseline; }
.lastbase { align-self: last baseline; }
.offset { margin-top: 10px;
margin-bottom: 3px; }
.lime { background: lime; }
.yellow { background: yellow; }
.orange { background: orange; }
.pink { background: pink; }
</style>
</head>
<body>
<div class="container">
<div class="lime base">one line (first)</div>
<div class="yellow lastbase">one line (last)</div>
<div class="orange offset lastbase">two<br/>lines and offset (last)</div>
<div class="pink offset base">offset (first)</div>
</div>
</body>
</html>

Просмотреть файл

@ -18,6 +18,8 @@
== flexbox-align-self-baseline-horiz-003.xhtml flexbox-align-self-baseline-horiz-003-ref.xhtml
== flexbox-align-self-baseline-horiz-004.xhtml flexbox-align-self-baseline-horiz-004-ref.xhtml
== flexbox-align-self-baseline-horiz-005.xhtml flexbox-align-self-baseline-horiz-005-ref.xhtml
== flexbox-align-self-baseline-horiz-006.xhtml flexbox-align-self-baseline-horiz-006-ref.xhtml
== flexbox-align-self-baseline-horiz-007.xhtml flexbox-align-self-baseline-horiz-007-ref.xhtml
== flexbox-align-self-stretch-vert-001.html flexbox-align-self-stretch-vert-001-ref.html
== flexbox-align-self-stretch-vert-002.html flexbox-align-self-stretch-vert-002-ref.html

Просмотреть файл

@ -391,7 +391,7 @@ public:
const gfxMatrix& aTransform,
const nsIntRect* aDirtyRect) override
{
BasicLayerManager* basic = static_cast<BasicLayerManager*>(mLayerManager);
BasicLayerManager* basic = mLayerManager->AsBasicLayerManager();
basic->SetTarget(&aContext);
gfxPoint devPixelOffset =
@ -850,7 +850,7 @@ nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams)
/* Paint the child */
context.SetMatrix(matrixAutoSaveRestore.Matrix());
BasicLayerManager* basic = static_cast<BasicLayerManager*>(aParams.layerManager);
BasicLayerManager* basic = aParams.layerManager->AsBasicLayerManager();
RefPtr<gfxContext> oldCtx = basic->GetTarget();
basic->SetTarget(&context);
aParams.layerManager->EndTransaction(FrameLayerBuilder::DrawPaintedLayer,

Просмотреть файл

@ -39,6 +39,14 @@ public abstract class StreamItem extends RecyclerView.ViewHolder {
super(itemView);
}
public static class HighlightsTitle extends StreamItem {
public static final int LAYOUT_ID = R.layout.activity_stream_main_highlightstitle;
public HighlightsTitle(View itemView) {
super(itemView);
}
}
public static class TopPanel extends StreamItem {
public static final int LAYOUT_ID = R.layout.activity_stream_main_toppanel;
@ -109,7 +117,9 @@ public abstract class StreamItem extends RecyclerView.ViewHolder {
menuButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ActivityStreamContextMenu.show(v.getContext(), ActivityStreamContextMenu.MenuMode.HIGHLIGHT,
ActivityStreamContextMenu.show(v.getContext(),
menuButton,
ActivityStreamContextMenu.MenuMode.HIGHLIGHT,
title, url, onUrlOpenListener, onUrlOpenInBackgroundListener,
vIconView.getWidth(), vIconView.getHeight());
}

Просмотреть файл

@ -47,6 +47,8 @@ public class StreamRecyclerAdapter extends RecyclerView.Adapter<StreamItem> impl
public int getItemViewType(int position) {
if (position == 0) {
return TopPanel.LAYOUT_ID;
} else if (position == 1) {
return StreamItem.HighlightsTitle.LAYOUT_ID;
} else {
return HighlightItem.LAYOUT_ID;
}
@ -58,6 +60,8 @@ public class StreamRecyclerAdapter extends RecyclerView.Adapter<StreamItem> impl
if (type == TopPanel.LAYOUT_ID) {
return new TopPanel(inflater.inflate(type, parent, false), onUrlOpenListener, onUrlOpenInBackgroundListener);
} else if (type == StreamItem.HighlightsTitle.LAYOUT_ID) {
return new StreamItem.HighlightsTitle(inflater.inflate(type, parent, false));
} else if (type == HighlightItem.LAYOUT_ID) {
return new HighlightItem(inflater.inflate(type, parent, false), onUrlOpenListener, onUrlOpenInBackgroundListener);
} else {
@ -70,8 +74,8 @@ public class StreamRecyclerAdapter extends RecyclerView.Adapter<StreamItem> impl
throw new IllegalArgumentException("Requested cursor position for invalid item");
}
// We have one blank panel at the top, hence remove that to obtain the cursor position
return position - 1;
// We have two blank panels at the top, hence remove that to obtain the cursor position
return position - 2;
}
@Override
@ -114,7 +118,7 @@ public class StreamRecyclerAdapter extends RecyclerView.Adapter<StreamItem> impl
highlightsCount = 0;
}
return highlightsCount + 1;
return highlightsCount + 2;
}
public void swapHighlightsCursor(Cursor cursor) {

Просмотреть файл

@ -8,37 +8,27 @@ import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomSheetBehavior;
import android.support.design.widget.BottomSheetDialog;
import android.support.design.widget.NavigationView;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.IntentHelper;
import org.mozilla.gecko.R;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
import org.mozilla.gecko.activitystream.ActivityStream;
import org.mozilla.gecko.annotation.RobocopTarget;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.home.HomePager;
import org.mozilla.gecko.icons.IconCallback;
import org.mozilla.gecko.icons.IconResponse;
import org.mozilla.gecko.icons.Icons;
import org.mozilla.gecko.util.Clipboard;
import org.mozilla.gecko.util.HardwareUtils;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.util.UIAsyncTask;
import org.mozilla.gecko.widget.FaviconView;
import java.util.EnumSet;
import static org.mozilla.gecko.activitystream.ActivityStream.extractLabel;
public class ActivityStreamContextMenu
extends BottomSheetDialog
@RobocopTarget
public abstract class ActivityStreamContextMenu
implements NavigationView.OnNavigationItemSelectedListener {
public enum MenuMode {
@ -54,66 +44,48 @@ public class ActivityStreamContextMenu
final HomePager.OnUrlOpenListener onUrlOpenListener;
final HomePager.OnUrlOpenInBackgroundListener onUrlOpenInBackgroundListener;
boolean isAlreadyBookmarked = false;
boolean isAlreadyBookmarked; // default false;
private ActivityStreamContextMenu(final Context context,
final MenuMode mode,
final String title, @NonNull final String url,
HomePager.OnUrlOpenListener onUrlOpenListener,
HomePager.OnUrlOpenInBackgroundListener onUrlOpenInBackgroundListener,
final int tilesWidth, final int tilesHeight) {
super(context);
public abstract MenuItem getItemByID(int id);
public abstract void show();
public abstract void dismiss();
final MenuMode mode;
/* package-private */ ActivityStreamContextMenu(final Context context,
final MenuMode mode,
final String title, @NonNull final String url,
HomePager.OnUrlOpenListener onUrlOpenListener,
HomePager.OnUrlOpenInBackgroundListener onUrlOpenInBackgroundListener) {
this.context = context;
this.mode = mode;
this.title = title;
this.url = url;
this.onUrlOpenListener = onUrlOpenListener;
this.onUrlOpenInBackgroundListener = onUrlOpenInBackgroundListener;
}
final LayoutInflater inflater = LayoutInflater.from(context);
final View content = inflater.inflate(R.layout.activity_stream_contextmenu_layout, null);
setContentView(content);
((TextView) findViewById(R.id.title)).setText(title);
extractLabel(context, url, false, new ActivityStream.LabelCallback() {
public void onLabelExtracted(String label) {
((TextView) findViewById(R.id.url)).setText(label);
}
});
// Copy layouted parameters from the Highlights / TopSites items to ensure consistency
final FaviconView faviconView = (FaviconView) findViewById(R.id.icon);
ViewGroup.LayoutParams layoutParams = faviconView.getLayoutParams();
layoutParams.width = tilesWidth;
layoutParams.height = tilesHeight;
faviconView.setLayoutParams(layoutParams);
Icons.with(context)
.pageUrl(url)
.skipNetwork()
.build()
.execute(new IconCallback() {
@Override
public void onIconResponse(IconResponse response) {
faviconView.updateImage(response);
}
});
NavigationView navigationView = (NavigationView) findViewById(R.id.menu);
navigationView.setNavigationItemSelectedListener(this);
/**
* Must be called before the menu is shown.
* <p/>
* Your implementation must be ready to return items from getItemByID() before postInit() is
* called, i.e. you should probably inflate your menu items before this call.
*/
protected void postInit() {
// Disable "dismiss" for topsites until we have decided on its behaviour for topsites
// (currently "dismiss" adds the URL to a highlights-specific blocklist, which the topsites
// query has no knowledge of).
if (mode == MenuMode.TOPSITE) {
final MenuItem dismissItem = navigationView.getMenu().findItem(R.id.dismiss);
final MenuItem dismissItem = getItemByID(R.id.dismiss);
dismissItem.setVisible(false);
}
// Disable the bookmark item until we know its bookmark state
final MenuItem bookmarkItem = navigationView.getMenu().findItem(R.id.bookmark);
final MenuItem bookmarkItem = getItemByID(R.id.bookmark);
bookmarkItem.setEnabled(false);
(new UIAsyncTask.WithoutParams<Void>(ThreadUtils.getBackgroundHandler()) {
@ -134,10 +106,9 @@ public class ActivityStreamContextMenu
}).execute();
// Only show the "remove from history" item if a page actually has history
final MenuItem deleteHistoryItem = navigationView.getMenu().findItem(R.id.delete);
final MenuItem deleteHistoryItem = getItemByID(R.id.delete);
deleteHistoryItem.setVisible(false);
(new UIAsyncTask.WithoutParams<Void>(ThreadUtils.getBackgroundHandler()) {
boolean hasHistory;
@ -164,26 +135,8 @@ public class ActivityStreamContextMenu
}
}
}).execute();
BottomSheetBehavior<View> bsBehaviour = BottomSheetBehavior.from((View) content.getParent());
bsBehaviour.setPeekHeight(context.getResources().getDimensionPixelSize(R.dimen.activity_stream_contextmenu_peek_height));
}
public static ActivityStreamContextMenu show(Context context,
final MenuMode menuMode,
final String title, @NonNull final String url,
HomePager.OnUrlOpenListener onUrlOpenListener,
HomePager.OnUrlOpenInBackgroundListener onUrlOpenInBackgroundListener,
final int tilesWidth, final int tilesHeight) {
final ActivityStreamContextMenu menu = new ActivityStreamContextMenu(context,
menuMode,
title, url,
onUrlOpenListener, onUrlOpenInBackgroundListener,
tilesWidth, tilesHeight);
menu.show();
return menu;
}
@Override
public boolean onNavigationItemSelected(MenuItem item) {
@ -254,4 +207,33 @@ public class ActivityStreamContextMenu
dismiss();
return true;
}
@RobocopTarget
public static ActivityStreamContextMenu show(Context context,
View anchor,
final MenuMode menuMode,
final String title, @NonNull final String url,
HomePager.OnUrlOpenListener onUrlOpenListener,
HomePager.OnUrlOpenInBackgroundListener onUrlOpenInBackgroundListener,
final int tilesWidth, final int tilesHeight) {
final ActivityStreamContextMenu menu;
if (!HardwareUtils.isTablet()) {
menu = new BottomSheetContextMenu(context,
menuMode,
title, url,
onUrlOpenListener, onUrlOpenInBackgroundListener,
tilesWidth, tilesHeight);
} else {
menu = new PopupContextMenu(context,
anchor,
menuMode,
title, url,
onUrlOpenListener, onUrlOpenInBackgroundListener);
}
menu.show();
return menu;
}
}

Просмотреть файл

@ -0,0 +1,102 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.home.activitystream.menu;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomSheetBehavior;
import android.support.design.widget.BottomSheetDialog;
import android.support.design.widget.NavigationView;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.mozilla.gecko.R;
import org.mozilla.gecko.activitystream.ActivityStream;
import org.mozilla.gecko.home.HomePager;
import org.mozilla.gecko.icons.IconCallback;
import org.mozilla.gecko.icons.IconResponse;
import org.mozilla.gecko.icons.Icons;
import org.mozilla.gecko.widget.FaviconView;
import static org.mozilla.gecko.activitystream.ActivityStream.extractLabel;
/* package-private */ class BottomSheetContextMenu
extends ActivityStreamContextMenu {
private final BottomSheetDialog bottomSheetDialog;
private final NavigationView navigationView;
public BottomSheetContextMenu(final Context context,
final MenuMode mode,
final String title, @NonNull final String url,
HomePager.OnUrlOpenListener onUrlOpenListener,
HomePager.OnUrlOpenInBackgroundListener onUrlOpenInBackgroundListener,
final int tilesWidth, final int tilesHeight) {
super(context,
mode,
title,
url,
onUrlOpenListener,
onUrlOpenInBackgroundListener);
final LayoutInflater inflater = LayoutInflater.from(context);
final View content = inflater.inflate(R.layout.activity_stream_contextmenu_bottomsheet, null);
bottomSheetDialog = new BottomSheetDialog(context);
bottomSheetDialog.setContentView(content);
((TextView) content.findViewById(R.id.title)).setText(title);
extractLabel(context, url, false, new ActivityStream.LabelCallback() {
public void onLabelExtracted(String label) {
((TextView) content.findViewById(R.id.url)).setText(label);
}
});
// Copy layouted parameters from the Highlights / TopSites items to ensure consistency
final FaviconView faviconView = (FaviconView) content.findViewById(R.id.icon);
ViewGroup.LayoutParams layoutParams = faviconView.getLayoutParams();
layoutParams.width = tilesWidth;
layoutParams.height = tilesHeight;
faviconView.setLayoutParams(layoutParams);
Icons.with(context)
.pageUrl(url)
.skipNetwork()
.build()
.execute(new IconCallback() {
@Override
public void onIconResponse(IconResponse response) {
faviconView.updateImage(response);
}
});
navigationView = (NavigationView) content.findViewById(R.id.menu);
navigationView.setNavigationItemSelectedListener(this);
super.postInit();
}
@Override
public MenuItem getItemByID(int id) {
return navigationView.getMenu().findItem(id);
}
@Override
public void show() {
bottomSheetDialog.show();
}
public void dismiss() {
bottomSheetDialog.dismiss();
}
}

Просмотреть файл

@ -0,0 +1,76 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.home.activitystream.menu;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.support.annotation.NonNull;
import android.support.design.widget.NavigationView;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.PopupWindow;
import org.mozilla.gecko.R;
import org.mozilla.gecko.home.HomePager;
/* package-private */ class PopupContextMenu
extends ActivityStreamContextMenu {
private final PopupWindow popupWindow;
private final NavigationView navigationView;
private final View anchor;
public PopupContextMenu(final Context context,
View anchor,
final MenuMode mode,
final String title,
@NonNull final String url,
HomePager.OnUrlOpenListener onUrlOpenListener,
HomePager.OnUrlOpenInBackgroundListener onUrlOpenInBackgroundListener) {
super(context,
mode,
title,
url,
onUrlOpenListener,
onUrlOpenInBackgroundListener);
this.anchor = anchor;
final LayoutInflater inflater = LayoutInflater.from(context);
View card = inflater.inflate(R.layout.activity_stream_contextmenu_popupmenu, null);
navigationView = (NavigationView) card.findViewById(R.id.menu);
navigationView.setNavigationItemSelectedListener(this);
popupWindow = new PopupWindow(context);
popupWindow.setContentView(card);
popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
popupWindow.setFocusable(true);
super.postInit();
}
@Override
public MenuItem getItemByID(int id) {
return navigationView.getMenu().findItem(id);
}
@Override
public void show() {
// By default popupWindow follows the pre-material convention of displaying the popup
// below a View. We need to shift it over the view:
popupWindow.showAsDropDown(anchor,
0,
-(anchor.getHeight() + anchor.getPaddingBottom()));
}
public void dismiss() {
popupWindow.dismiss();
}
}

Просмотреть файл

@ -92,6 +92,7 @@ class TopSitesCard extends RecyclerView.ViewHolder
onUrlOpenListener.onUrlOpen(url, EnumSet.noneOf(HomePager.OnUrlOpenListener.Flags.class));
} else if (clickedView == menuButton) {
ActivityStreamContextMenu.show(clickedView.getContext(),
menuButton,
ActivityStreamContextMenu.MenuMode.TOPSITE,
title.getText().toString(), url,
onUrlOpenListener, onUrlOpenInBackgroundListener,

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше