MozReview-Commit-ID: 8nqgw9Q3gSY
This commit is contained in:
Phil Ringnalda 2016-10-25 22:07:07 -07:00
Родитель 17a0c4983e 8cf1367dd8
Коммит 435a27119b
157 изменённых файлов: 6122 добавлений и 4355 удалений

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

@ -673,7 +673,7 @@ ia2Accessible::get_selectionRanges(IA2Range** aRanges,
{
A11Y_TRYBLOCK_BEGIN
if (!aRanges || !aNRanges || aNRanges <= 0)
if (!aRanges || !aNRanges)
return E_INVALIDARG;
*aNRanges = 0;

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

@ -496,8 +496,27 @@ var LightWeightThemeWebInstaller = {
return;
}
let uri = makeURI(baseURI);
// A notification bar with the option to undo is normally shown after a
// theme is installed. But the discovery pane served from the url(s)
// below has its own toggle switch for quick undos, so don't show the
// notification in that case.
let notify = uri.prePath != "https://discovery.addons.mozilla.org";
if (notify) {
try {
if (Services.prefs.getBoolPref("extensions.webapi.testing")
&& (uri.prePath == "https://discovery.addons.allizom.org"
|| uri.prePath == "https://discovery.addons-dev.allizom.org")) {
notify = false;
}
} catch (e) {
// getBoolPref() throws if the testing pref isn't set. ignore it.
}
}
if (this._isAllowed(baseURI)) {
this._install(data);
this._install(data, notify);
return;
}
@ -507,12 +526,12 @@ var LightWeightThemeWebInstaller = {
gNavigatorBundle.getString("lwthemeInstallRequest.allowButton.accesskey");
let message =
gNavigatorBundle.getFormattedString("lwthemeInstallRequest.message",
[makeURI(baseURI).host]);
[uri.host]);
let buttons = [{
label: allowButtonText,
accessKey: allowButtonAccesskey,
callback: function () {
LightWeightThemeWebInstaller._install(data);
LightWeightThemeWebInstaller._install(data, notify);
}
}];
@ -526,7 +545,7 @@ var LightWeightThemeWebInstaller = {
notificationBar.persistence = 1;
},
_install: function (newLWTheme) {
_install: function (newLWTheme, notify) {
let previousLWTheme = this._manager.currentTheme;
let listener = {
@ -556,7 +575,9 @@ var LightWeightThemeWebInstaller = {
},
onEnabled: function(aAddon) {
LightWeightThemeWebInstaller._postInstallNotification(newLWTheme, previousLWTheme);
if (notify) {
LightWeightThemeWebInstaller._postInstallNotification(newLWTheme, previousLWTheme);
}
}
};

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

@ -520,6 +520,10 @@ toolbar:not(#TabsToolbar) > #personal-bookmarks {
transition: none;
}
#DateTimePickerPanel {
-moz-binding: url("chrome://global/content/bindings/datetimepopup.xml#datetime-popup");
}
#urlbar[pageproxystate="invalid"] > #urlbar-icons > .urlbar-icon,
#urlbar[pageproxystate="invalid"][focused="true"] > #urlbar-go-button ~ toolbarbutton,
#urlbar[pageproxystate="valid"] > #urlbar-go-button,

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

@ -141,7 +141,12 @@
<tooltip id="remoteBrowserTooltip"/>
<!-- for search and content formfill/pw manager -->
<panel type="autocomplete-richlistbox" id="PopupAutoComplete" noautofocus="true" hidden="true"/>
<panel type="autocomplete-richlistbox"
id="PopupAutoComplete"
noautofocus="true"
hidden="true"
norolluponanchor="true" />
<!-- for search with one-off buttons -->
<panel type="autocomplete" id="PopupSearchAutoComplete" noautofocus="true" hidden="true"/>
@ -155,10 +160,14 @@
level="parent"/>
<panel id="DateTimePickerPanel"
type="arrow"
hidden="true"
orient="vertical"
noautofocus="true"
consumeoutsideclicks="false"
level="parent"/>
level="parent">
<iframe id="dateTimePopupFrame"/>
</panel>
<!-- for select dropdowns. The menupopup is what shows the list of options,
and the popuponly menulist makes things like the menuactive attributes

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

@ -1372,15 +1372,15 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
<body><![CDATA[
this._oneOffSearchesEnabled = enable;
if (enable) {
this.oneOffSearchButtons.telemetryOrigin = "urlbar";
this.oneOffSearchButtons.style.display = "-moz-box";
this.oneOffSearchButtons.popup = this;
this.oneOffSearchButtons.textbox = this.input;
this.oneOffSearchButtons.telemetryOrigin = "urlbar";
} else {
this.oneOffSearchButtons.telemetryOrigin = null;
this.oneOffSearchButtons.style.display = "none";
this.oneOffSearchButtons.popup = null;
this.oneOffSearchButtons.textbox = null;
this.oneOffSearchButtons.telemetryOrigin = null;
}
]]></body>
</method>

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

@ -2,6 +2,8 @@
* 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/. */
/* eslint no-undef:2 */
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/AppConstants.jsm");
@ -231,7 +233,7 @@ function openPreferences() {
.createInstance(Components.interfaces.nsISupportsString);
wuri.data = "about:preferences";
sa.appendElement(wuri, /*weak =*/ false);
args.appendElement(wuri, /*weak =*/ false);
Services.ww.openWindow(null, gBrowserContentHandler.chromeURL,
"_blank",

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

@ -976,10 +976,12 @@
);
this.style.minWidth = minWidth + "px";
// Set the origin before assigning the popup, as the assignment does
// a rebuild and would miss the origin.
this.oneOffButtons.telemetryOrigin = "searchbar";
// Set popup after setting the minWidth since it builds the buttons.
this.oneOffButtons.popup = this;
this.oneOffButtons.textbox = this.input;
this.oneOffButtons.telemetryOrigin = "searchbar";
}
// First handle deciding if we are showing the reduced version of the
@ -2026,17 +2028,19 @@
if (anonid == "search-one-offs-context-set-default") {
let currentEngine = Services.search.currentEngine;
// Make the target button of the context menu reflect the current
// search engine first. Doing this as opposed to rebuilding all the
// one-off buttons avoids flicker.
let button = this._buttonForEngine(this._contextEngine);
button.id = this._buttonIDForEngine(currentEngine);
let uri = "chrome://browser/skin/search-engine-placeholder.png";
if (currentEngine.iconURI)
uri = currentEngine.iconURI.spec;
button.setAttribute("image", uri);
button.setAttribute("tooltiptext", currentEngine.name);
button.engine = currentEngine;
if (!this.getAttribute("includecurrentengine")) {
// Make the target button of the context menu reflect the current
// search engine first. Doing this as opposed to rebuilding all the
// one-off buttons avoids flicker.
let button = this._buttonForEngine(this._contextEngine);
button.id = this._buttonIDForEngine(currentEngine);
let uri = "chrome://browser/skin/search-engine-placeholder.png";
if (currentEngine.iconURI)
uri = currentEngine.iconURI.spec;
button.setAttribute("image", uri);
button.setAttribute("tooltiptext", currentEngine.name);
button.engine = currentEngine;
}
Services.search.currentEngine = this._contextEngine;
}

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

@ -30,6 +30,7 @@ skip-if = os == "mac" # bug 967013
[browser_hiddenOneOffs_cleanup.js]
[browser_hiddenOneOffs_diacritics.js]
[browser_oneOffContextMenu.js]
[browser_oneOffContextMenu_setDefault.js]
[browser_oneOffHeader.js]
[browser_private_search_perwindowpb.js]
[browser_yahoo.js]

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

@ -0,0 +1,189 @@
"use strict";
const TEST_ENGINE_NAME = "Foo";
const TEST_ENGINE_BASENAME = "testEngine.xml";
const SEARCHBAR_BASE_ID = "searchbar-engine-one-off-item-";
const URLBAR_BASE_ID = "urlbar-engine-one-off-item-";
const searchbar = document.getElementById("searchbar");
const urlbar = document.getElementById("urlbar");
const searchPopup = document.getElementById("PopupSearchAutoComplete");
const urlbarPopup = document.getElementById("PopupAutoCompleteRichResult");
const searchIcon = document.getAnonymousElementByAttribute(
searchbar, "anonid", "searchbar-search-button"
);
const searchOneOffBinding = document.getAnonymousElementByAttribute(
searchPopup, "anonid", "search-one-off-buttons"
);
const urlBarOneOffBinding = document.getAnonymousElementByAttribute(
urlbarPopup, "anonid", "one-off-search-buttons"
);
let originalEngine = Services.search.currentEngine;
function resetEngine() {
Services.search.currentEngine = originalEngine;
}
registerCleanupFunction(resetEngine);
add_task(function* init() {
yield promiseNewEngine(TEST_ENGINE_BASENAME, {
setAsCurrent: false,
});
});
add_task(function* test_searchBarChangeEngine() {
let oneOffButton = yield openPopupAndGetEngineButton(true, searchPopup,
searchOneOffBinding,
SEARCHBAR_BASE_ID);
const setDefaultEngineMenuItem = document.getAnonymousElementByAttribute(
searchOneOffBinding, "anonid", "search-one-offs-context-set-default"
);
// Click the set default engine menu item.
let promise = promiseCurrentEngineChanged();
EventUtils.synthesizeMouseAtCenter(setDefaultEngineMenuItem, {});
// This also checks the engine correctly changed.
yield promise;
Assert.equal(oneOffButton.id, SEARCHBAR_BASE_ID + originalEngine.name,
"Should now have the original engine's id for the button");
Assert.equal(oneOffButton.getAttribute("tooltiptext"), originalEngine.name,
"Should now have the original engine's name for the tooltip");
Assert.equal(oneOffButton.image, originalEngine.iconURI.spec,
"Should now have the original engine's uri for the image");
yield promiseClosePopup(searchPopup);
});
add_task(function* test_urlBarChangeEngine() {
// Ensure the engine is reset.
resetEngine();
let oneOffButton = yield openPopupAndGetEngineButton(false, urlbarPopup,
urlBarOneOffBinding,
URLBAR_BASE_ID);
const setDefaultEngineMenuItem = document.getAnonymousElementByAttribute(
urlBarOneOffBinding, "anonid", "search-one-offs-context-set-default"
);
// Click the set default engine menu item.
let promise = promiseCurrentEngineChanged();
EventUtils.synthesizeMouseAtCenter(setDefaultEngineMenuItem, {});
// This also checks the engine correctly changed.
yield promise;
let currentEngine = Services.search.currentEngine;
// For the urlbar, we should keep the new engine's icon.
Assert.equal(oneOffButton.id, URLBAR_BASE_ID + currentEngine.name,
"Should now have the original engine's id for the button");
Assert.equal(oneOffButton.getAttribute("tooltiptext"), currentEngine.name,
"Should now have the original engine's name for the tooltip");
Assert.equal(oneOffButton.image, currentEngine.iconURI.spec,
"Should now have the original engine's uri for the image");
yield promiseClosePopup(urlbarPopup);
});
/**
* Promises that an engine change has happened for the current engine, which
* has resulted in the test engine now being the current engine.
*
* @return {Promise} Resolved once the test engine is set as the current engine.
*/
function promiseCurrentEngineChanged() {
return new Promise(resolve => {
function observer(aSub, aTopic, aData) {
if (aData == "engine-current") {
Assert.ok(Services.search.currentEngine.name, TEST_ENGINE_NAME, "currentEngine set");
Services.obs.removeObserver(observer, "browser-search-engine-modified");
resolve();
}
}
Services.obs.addObserver(observer, "browser-search-engine-modified", false);
});
}
/**
* Opens the specified urlbar/search popup and gets the test engine from the
* one-off buttons.
*
* @param {Boolean} isSearch true if the search popup should be opened; false
* for the urlbar popup.
* @param {Object} popup The expected popup.
* @param {Object} oneOffBinding The expected one-off-binding for the popup.
* @param {String} baseId The expected string for the id of the current
* engine button, without the engine name.
* @return {Object} Returns an object that represents the one off button for the
* test engine.
*/
function* openPopupAndGetEngineButton(isSearch, popup, oneOffBinding, baseId) {
// Open the popup.
let promise = promiseEvent(popup, "popupshown");
info("Opening panel");
// We have to open the popups in differnt ways.
if (isSearch) {
// Use the search icon to avoid hitting the network.
EventUtils.synthesizeMouseAtCenter(searchIcon, {});
} else {
// There's no history at this stage, so we need to press a key.
urlbar.focus();
EventUtils.synthesizeKey("a", {});
}
yield promise;
const contextMenu = document.getAnonymousElementByAttribute(
oneOffBinding, "anonid", "search-one-offs-context-menu"
);
const oneOffButtons = document.getAnonymousElementByAttribute(
oneOffBinding, "anonid", "search-panel-one-offs"
);
// Get the one-off button for the test engine.
let oneOffButton;
for (let node of oneOffButtons.childNodes) {
if (node.engine && node.engine.name == TEST_ENGINE_NAME) {
oneOffButton = node;
break;
}
}
Assert.notEqual(oneOffButton, undefined,
"One-off for test engine should exist");
Assert.equal(oneOffButton.getAttribute("tooltiptext"), TEST_ENGINE_NAME,
"One-off should have the tooltip set to the engine name");
Assert.equal(oneOffButton.id, baseId + TEST_ENGINE_NAME,
"Should have the correct id");
// Open the context menu on the one-off.
promise = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
EventUtils.synthesizeMouseAtCenter(oneOffButton, {
type: "contextmenu",
button: 2,
});
yield promise;
return oneOffButton;
}
/**
* Closes the popup and moves the mouse away from it.
*
* @param {Button} popup The popup to close.
*/
function* promiseClosePopup(popup) {
// close the panel using the escape key.
let promise = promiseEvent(popup, "popuphidden");
EventUtils.synthesizeKey("VK_ESCAPE", {});
yield promise;
// Move the cursor out of the panel area to avoid messing with other tests.
yield EventUtils.synthesizeNativeMouseMove(popup);
}

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

@ -0,0 +1,11 @@
"use strict";
module.exports = {
"rules": {
"no-unused-vars": ["error", {
"vars": "all",
"varsIgnorePattern": "^(Cc|Ci|Cr|Cu|EXPORTED_SYMBOLS)$",
"args": "none"
}]
}
};

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

@ -44,7 +44,6 @@ const MANIFEST_VERSION = 1;
const CACHE_VERSION = 1;
const KEEP_HISTORY_N_DAYS = 180;
const MIN_EXPERIMENT_ACTIVE_SECONDS = 60;
const PREF_BRANCH = "experiments.";
const PREF_ENABLED = "enabled"; // experiments.enabled
@ -1217,7 +1216,6 @@ Experiments.Experiments.prototype = {
let activeExperiment = this._getActiveExperiment();
let activeChanged = false;
let now = this._policy.now();
if (!activeExperiment) {
// Avoid this pref staying out of sync if there were e.g. crashes.
@ -1277,7 +1275,6 @@ Experiments.Experiments.prototype = {
if (!applicable && reason && reason[0] != "was-active") {
// Report this from here to avoid over-reporting.
let desc = TELEMETRY_LOG.ACTIVATION;
let data = [TELEMETRY_LOG.ACTIVATION.REJECTED, id];
data = data.concat(reason);
const key = TELEMETRY_LOG.ACTIVATION_KEY;
@ -1343,7 +1340,7 @@ Experiments.Experiments.prototype = {
time = now + 1000 * CACHE_WRITE_RETRY_DELAY_SEC;
}
for (let [id, experiment] of this._experiments) {
for (let [, experiment] of this._experiments) {
let scheduleTime = experiment.getScheduleTime();
if (scheduleTime > now) {
if (time !== null) {
@ -1644,7 +1641,6 @@ Experiments.ExperimentEntry.prototype = {
let data = this._manifestData;
let now = this._policy.now() / 1000; // The manifest times are in seconds.
let minActive = MIN_EXPERIMENT_ACTIVE_SECONDS;
let maxActive = data.maxActiveSeconds || 0;
let startSec = (this.startDate || 0) / 1000;
@ -2069,10 +2065,6 @@ Experiments.ExperimentEntry.prototype = {
throw new Error("shouldStop must not be called on disabled experiments.");
}
let data = this._manifestData;
let now = this._policy.now() / 1000; // The manifest times are in seconds.
let maxActiveSec = data.maxActiveSeconds || 0;
let deferred = Promise.defer();
this.isApplicable().then(
() => deferred.resolve({shouldStop: false}),
@ -2097,7 +2089,6 @@ Experiments.ExperimentEntry.prototype = {
*/
getScheduleTime: function () {
if (this._enabled) {
let now = this._policy.now();
let startTime = this._startDate.getTime();
let maxActiveTime = startTime + 1000 * this._manifestData.maxActiveSeconds;
return Math.min(1000 * this._manifestData.endTime, maxActiveTime);
@ -2228,7 +2219,7 @@ this.Experiments.PreviousExperimentProvider.prototype = Object.freeze({
for (let id of removed) {
this._log.trace("updateExperimentList() - removing " + id);
let wrapper = new PreviousExperimentAddon(oldMap.get(id));
AddonManagerPrivate.callAddonListeners("onUninstalling", plugin, false);
AddonManagerPrivate.callAddonListeners("onUninstalling", wrapper, false);
}
this._experimentList = list;

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

@ -1,3 +1,5 @@
/* exported startup, shutdown, install, uninstall */
var {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource:///modules/experiments/Experiments.jsm");

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

@ -3,5 +3,13 @@
module.exports = {
"extends": [
"../../../../testing/xpcshell/xpcshell.eslintrc.js"
]
],
"rules": {
"no-unused-vars": ["error", {
"vars": "all",
"varsIgnorePattern": "^(Cc|Ci|Cr|Cu|EXPORTED_SYMBOLS|run_test)$",
"args": "none"
}]
}
};

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

@ -1,6 +1,15 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/* exported PREF_EXPERIMENTS_ENABLED, PREF_LOGGING_LEVEL, PREF_LOGGING_DUMP
PREF_MANIFEST_URI, PREF_FETCHINTERVAL, EXPERIMENT1_ID,
EXPERIMENT1_NAME, EXPERIMENT1_XPI_SHA1, EXPERIMENT1A_NAME,
EXPERIMENT1A_XPI_SHA1, EXPERIMENT2_ID, EXPERIMENT2_XPI_SHA1,
EXPERIMENT3_ID, EXPERIMENT4_ID, FAKE_EXPERIMENTS_1,
FAKE_EXPERIMENTS_2, gAppInfo, removeCacheFile, defineNow,
futureDate, dateToSeconds, loadAddonManager, promiseRestartManager,
startAddonManagerOnly, getExperimentAddons, replaceExperiments */
var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/Services.jsm");

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

@ -6,11 +6,9 @@
Cu.import("resource://testing-common/httpd.js");
Cu.import("resource:///modules/experiments/Experiments.jsm");
const FILE_MANIFEST = "experiments.manifest";
const SEC_IN_ONE_DAY = 24 * 60 * 60;
const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000;
var gProfileDir = null;
var gHttpServer = null;
var gHttpRoot = null;
var gPolicy = null;
@ -32,7 +30,6 @@ function run_test() {
add_task(function* test_setup() {
loadAddonManager();
gProfileDir = do_get_profile();
gPolicy = new Experiments.Policy();
gHttpServer = new HttpServer();
@ -49,8 +46,6 @@ add_task(function* test_setup() {
Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true);
Services.prefs.setIntPref(PREF_LOGGING_LEVEL, 0);
Services.prefs.setBoolPref(PREF_LOGGING_DUMP, true);
let experiments = new Experiments.Experiments();
});
function isApplicable(experiment) {

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

@ -9,13 +9,11 @@ Cu.import("resource://testing-common/AddonManagerTesting.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Experiments",
"resource:///modules/experiments/Experiments.jsm");
const FILE_MANIFEST = "experiments.manifest";
const MANIFEST_HANDLER = "manifests/handler";
const SEC_IN_ONE_DAY = 24 * 60 * 60;
const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000;
var gProfileDir = null;
var gHttpServer = null;
var gHttpRoot = null;
var gDataRoot = null;
@ -47,7 +45,6 @@ function run_test() {
add_task(function* test_setup() {
loadAddonManager();
gProfileDir = do_get_profile();
gHttpServer = new HttpServer();
gHttpServer.start(-1);
@ -162,7 +159,7 @@ add_task(function* test_getExperiments() {
Assert.equal(addons.length, 0, "Precondition: No experiment add-ons are installed.");
try {
let b = yield experiments.getExperimentBranch();
yield experiments.getExperimentBranch();
Assert.ok(false, "getExperimentBranch should fail with no experiment");
}
catch (e) {

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

@ -12,14 +12,12 @@ const MANIFEST_HANDLER = "manifests/handler";
const SEC_IN_ONE_DAY = 24 * 60 * 60;
const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000;
var gProfileDir = null;
var gHttpServer = null;
var gHttpRoot = null;
var gDataRoot = null;
var gPolicy = null;
var gManifestObject = null;
var gManifestHandlerURI = null;
var gTimerScheduleOffset = -1;
function run_test() {
run_next_test();
@ -27,7 +25,6 @@ function run_test() {
add_task(function* test_setup() {
loadAddonManager();
gProfileDir = do_get_profile();
yield removeCacheFile();
gHttpServer = new HttpServer();
@ -54,7 +51,7 @@ add_task(function* test_setup() {
gPolicy = new Experiments.Policy();
patchPolicy(gPolicy, {
updatechannel: () => "nightly",
oneshotTimer: (callback, timeout, thisObj, name) => gTimerScheduleOffset = timeout,
oneshotTimer: (callback, timeout, thisObj, name) => {},
});
});

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

@ -11,7 +11,6 @@ const MANIFEST_HANDLER = "manifests/handler";
const SEC_IN_ONE_DAY = 24 * 60 * 60;
const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000;
var gProfileDir = null;
var gHttpServer = null;
var gHttpRoot = null;
var gDataRoot = null;
@ -25,7 +24,6 @@ function run_test() {
add_task(function* test_setup() {
loadAddonManager();
gProfileDir = do_get_profile();
yield removeCacheFile();
gHttpServer = new HttpServer();

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

@ -7,16 +7,10 @@
Cu.import("resource:///modules/experiments/Experiments.jsm");
Cu.import("resource://gre/modules/TelemetryController.jsm", this);
const FILE_MANIFEST = "experiments.manifest";
const SEC_IN_ONE_DAY = 24 * 60 * 60;
const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000;
var gProfileDir = null;
var gHttpServer = null;
var gHttpRoot = null;
var gPolicy = null;
function ManifestEntry(data) {
this.id = EXPERIMENT1_ID;
this.xpiURL = "http://localhost:1/dummy.xpi";
@ -50,7 +44,7 @@ function run_test() {
add_task(function* test_setup() {
createAppInfo();
gProfileDir = do_get_profile();
do_get_profile();
startAddonManagerOnly();
yield TelemetryController.testSetup();
gPolicy = new Experiments.Policy();

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

@ -9,13 +9,11 @@ Cu.import("resource://testing-common/AddonManagerTesting.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Experiments",
"resource:///modules/experiments/Experiments.jsm");
const FILE_MANIFEST = "experiments.manifest";
const MANIFEST_HANDLER = "manifests/handler";
const SEC_IN_ONE_DAY = 24 * 60 * 60;
const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000;
var gProfileDir = null;
var gHttpServer = null;
var gHttpRoot = null;
var gDataRoot = null;
@ -29,7 +27,6 @@ function run_test() {
add_task(function* test_setup() {
loadAddonManager();
gProfileDir = do_get_profile();
gHttpServer = new HttpServer();
gHttpServer.start(-1);

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

@ -8,14 +8,12 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/osfile.jsm");
Cu.import("resource:///modules/experiments/Experiments.jsm");
var gProfileDir = null;
var gHttpServer = null;
var gHttpRoot = null;
var gPolicy = new Experiments.Policy();
function run_test() {
loadAddonManager();
gProfileDir = do_get_profile();
gHttpServer = new HttpServer();
gHttpServer.start(-1);
@ -68,4 +66,3 @@ add_task(function* test_fetchInvalid() {
yield promiseRestartManager();
});

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

@ -8,14 +8,12 @@ Cu.import("resource://gre/modules/TelemetryLog.jsm");
var bsp = Cu.import("resource:///modules/experiments/Experiments.jsm");
const FILE_MANIFEST = "experiments.manifest";
const MANIFEST_HANDLER = "manifests/handler";
const SEC_IN_ONE_DAY = 24 * 60 * 60;
const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000;
var gProfileDir = null;
var gHttpServer = null;
var gHttpRoot = null;
var gDataRoot = null;
@ -48,7 +46,6 @@ function run_test() {
add_task(function* test_setup() {
loadAddonManager();
gProfileDir = do_get_profile();
gHttpServer = new HttpServer();
gHttpServer.start(-1);
@ -87,8 +84,6 @@ add_task(function* test_telemetryBasics() {
// Check TelemetryLog instead of TelemetrySession.getPayload().log because
// TelemetrySession gets Experiments.instance() and side-effects log entries.
const OBSERVER_TOPIC = "experiments-changed";
let observerFireCount = 0;
let expectedLogLength = 0;
// Dates the following tests are based on.
@ -127,21 +122,6 @@ add_task(function* test_telemetryBasics() {
],
};
// Data to compare the result of Experiments.getExperiments() against.
let experimentListData = [
{
id: EXPERIMENT2_ID,
name: "Test experiment 2",
description: "And yet another experiment that experiments experimentally.",
},
{
id: EXPERIMENT1_ID,
name: EXPERIMENT1_NAME,
description: "Yet another experiment that experiments experimentally.",
},
];
let experiments = new Experiments.Experiments(gPolicy);
// Trigger update, clock set to before any activation.

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

@ -4,9 +4,6 @@
"use strict";
Cu.import("resource:///modules/experiments/Experiments.jsm");
const SEC_IN_ONE_DAY = 24 * 60 * 60;
const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000;
var cacheData = {
_enabled: true,
_manifestData: {

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

@ -114,6 +114,16 @@ this.TabCrashHandler = {
this.unseenCrashedChildIDs.shift();
}
}
// check for environment affecting crash reporting
let env = Cc["@mozilla.org/process/environment;1"]
.getService(Ci.nsIEnvironment);
let shutdown = env.exists("MOZ_CRASHREPORTER_SHUTDOWN");
if (shutdown) {
Services.startup.quit(Ci.nsIAppStartup.eForceQuit);
}
break;
}
case "oop-frameloader-crashed": {

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

@ -918,6 +918,10 @@ notification[value="translation"] menulist > .menulist-dropmarker {
%include ../shared/autocomplete.inc.css
#PopupAutoComplete > richlistbox > richlistitem[originaltype~="datalist-first"] {
border-top: 1px solid ThreeDShadow;
}
#treecolAutoCompleteImage {
max-width : 36px;
}

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

@ -1752,6 +1752,10 @@ toolbar .toolbarbutton-1 > .toolbarbutton-menubutton-button {
%include ../shared/autocomplete.inc.css
#PopupAutoComplete > richlistbox > richlistitem[originaltype~="datalist-first"] {
border-top: 1px solid #C7C7C7;
}
#treecolAutoCompleteImage {
max-width: 36px;
}

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

@ -7,7 +7,9 @@
#PopupAutoComplete > richlistbox > richlistitem {
height: 20px;
min-height: 20px;
border: 0;
border-radius: 0;
padding: 0px 1px 0px 1px;
}
#PopupAutoComplete > richlistbox > richlistitem > .ac-title {

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

@ -1534,6 +1534,10 @@ html|*.urlbar-input:-moz-lwtheme::placeholder,
%include ../shared/autocomplete.inc.css
#PopupAutoComplete > richlistbox > richlistitem[originaltype~="datalist-first"] {
border-top: 1px solid ThreeDShadow;
}
#treecolAutoCompleteImage {
max-width: 36px;
}

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

@ -159,15 +159,20 @@ js_option('--with-toolchain-prefix', env='TOOLCHAIN_PREFIX', nargs=1,
@depends('--with-toolchain-prefix', target, host, cross_compiling)
def toolchain_prefix(value, target, host, cross_compiling):
if value:
return value[0]
# Special case x86-64 <-> x86 cross compiling until we have the right tests
# in moz.configure land.
if cross_compiling and not all(i.cpu in ('x86_64', 'x86')
for i in (target, host)):
return '%s-' % target.toolchain
return tuple(value)
if cross_compiling:
return ('%s-' % target.toolchain, '%s-' % target.alias)
set_config('TOOLCHAIN_PREFIX', toolchain_prefix)
add_old_configure_assignment('TOOLCHAIN_PREFIX', toolchain_prefix)
@depends(toolchain_prefix, target)
def first_toolchain_prefix(toolchain_prefix, target):
# Pass TOOLCHAIN_PREFIX down to the build system if it was given from the
# command line/environment (in which case there's only one value in the tuple),
# or when cross-compiling for Android.
if toolchain_prefix and (target.os == 'Android' or len(toolchain_prefix) == 1):
return toolchain_prefix[0]
set_config('TOOLCHAIN_PREFIX', first_toolchain_prefix)
add_old_configure_assignment('TOOLCHAIN_PREFIX', first_toolchain_prefix)
# Compilers
@ -463,15 +468,17 @@ def default_c_compilers(host_or_target):
'''
assert host_or_target in (host, target)
@depends(host_or_target, host, toolchain_prefix)
def default_c_compilers(host_or_target, host, toolchain_prefix):
@depends(host_or_target, target, toolchain_prefix)
def default_c_compilers(host_or_target, target, toolchain_prefix):
gcc = ('gcc',)
if toolchain_prefix and host_or_target is target:
gcc = tuple('%sgcc' % p for p in toolchain_prefix) + gcc
if host_or_target.kernel == 'WINNT':
return ('cl', 'clang-cl', 'gcc', 'clang')
return ('cl', 'clang-cl') + gcc + ('clang',)
if host_or_target.kernel == 'Darwin':
return ('clang',)
if host_or_target != host: # cross compilation
return ('%sgcc' % toolchain_prefix, 'gcc', 'clang')
return ('gcc', 'clang')
return gcc + ('clang',)
return default_c_compilers

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

@ -3,20 +3,60 @@
"use strict";
// Test global exit button
const TEST_URL = "data:text/html;charset=utf-8,";
addRDMTask(TEST_URL, function* ({ ui, manager }) {
let { toolWindow } = ui;
let { store } = toolWindow;
// Test global exit button
addRDMTask(TEST_URL, function* (...args) {
yield testExitButton(...args);
});
// Wait until the viewport has been added
// Test global exit button on detached tab.
// See Bug 1262806
add_task(function* () {
let tab = yield addTab(TEST_URL);
let { ui, manager } = yield openRDM(tab);
yield waitBootstrap(ui);
let waitTabIsDetached = Promise.all([
once(tab, "TabClose"),
once(tab.linkedBrowser, "SwapDocShells")
]);
// Detach the tab with RDM open.
let newWindow = gBrowser.replaceTabWithWindow(tab);
// Waiting the tab is detached.
yield waitTabIsDetached;
// Get the new tab instance.
tab = newWindow.gBrowser.tabs[0];
// Detaching a tab closes RDM.
ok(!manager.isActiveForTab(tab),
"Responsive Design Mode is not active for the tab");
// Reopen the RDM and test the exit button again.
yield testExitButton(yield openRDM(tab));
yield BrowserTestUtils.closeWindow(newWindow);
});
function* waitBootstrap(ui) {
let { toolWindow, tab } = ui;
let { store } = toolWindow;
let url = String(tab.linkedBrowser.currentURI.spec);
// Wait until the viewport has been added.
yield waitUntilState(store, state => state.viewports.length == 1);
let exitButton = toolWindow.document.getElementById("global-exit-button");
// Wait until the document has been loaded.
yield waitForFrameLoad(ui, url);
}
yield waitForFrameLoad(ui, TEST_URL);
function* testExitButton({ui, manager}) {
yield waitBootstrap(ui);
let exitButton = ui.toolWindow.document.getElementById("global-exit-button");
ok(manager.isActiveForTab(ui.tab),
"Responsive Design Mode active for the tab");
@ -27,4 +67,4 @@ addRDMTask(TEST_URL, function* ({ ui, manager }) {
ok(!manager.isActiveForTab(ui.tab),
"Responsive Design Mode is not active for the tab");
});
}

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

@ -41,7 +41,8 @@ var global = this;
function startResponsiveMode({data:data}) {
debug("START");
if (active) {
debug("ALREADY STARTED, ABORT");
debug("ALREADY STARTED");
sendAsyncMessage("ResponsiveMode:Start:Done");
return;
}
addMessageListener("ResponsiveMode:RequestScreenshot", screenshot);

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

@ -291,7 +291,7 @@ KeyframeEffectReadOnly::UpdateProperties(nsStyleContext* aStyleContext)
if (mEffectOptions.mSpacingMode == SpacingMode::paced) {
KeyframeUtils::ApplySpacing(keyframesCopy, SpacingMode::paced,
mEffectOptions.mPacedProperty,
computedValues);
computedValues, aStyleContext);
}
properties =

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

@ -417,7 +417,8 @@ PaceRange(const Range<Keyframe>& aKeyframes,
static nsTArray<double>
GetCumulativeDistances(const nsTArray<ComputedKeyframeValues>& aValues,
nsCSSPropertyID aProperty);
nsCSSPropertyID aProperty,
nsStyleContext* aStyleContext);
// ------------------------------------------------------------------
//
@ -481,7 +482,8 @@ KeyframeUtils::GetKeyframesFromObject(JSContext* aCx,
KeyframeUtils::ApplySpacing(nsTArray<Keyframe>& aKeyframes,
SpacingMode aSpacingMode,
nsCSSPropertyID aProperty,
nsTArray<ComputedKeyframeValues>& aComputedValues)
nsTArray<ComputedKeyframeValues>& aComputedValues,
nsStyleContext* aStyleContext)
{
if (aKeyframes.IsEmpty()) {
return;
@ -492,7 +494,8 @@ KeyframeUtils::ApplySpacing(nsTArray<Keyframe>& aKeyframes,
MOZ_ASSERT(IsAnimatableProperty(aProperty),
"Paced property should be animatable");
cumulativeDistances = GetCumulativeDistances(aComputedValues, aProperty);
cumulativeDistances = GetCumulativeDistances(aComputedValues, aProperty,
aStyleContext);
// Reset the computed offsets if using paced spacing.
for (Keyframe& keyframe : aKeyframes) {
keyframe.mComputedOffset = Keyframe::kComputedOffsetNotSet;
@ -583,7 +586,7 @@ KeyframeUtils::ApplyDistributeSpacing(nsTArray<Keyframe>& aKeyframes)
{
nsTArray<ComputedKeyframeValues> emptyArray;
ApplySpacing(aKeyframes, SpacingMode::distribute, eCSSProperty_UNKNOWN,
emptyArray);
emptyArray, nullptr);
}
/* static */ nsTArray<ComputedKeyframeValues>
@ -1561,12 +1564,14 @@ PaceRange(const Range<Keyframe>& aKeyframes,
*
* @param aValues The computed values returned by GetComputedKeyframeValues.
* @param aPacedProperty The paced property.
* @param aStyleContext The style context for computing distance on transform.
* @return The cumulative distances for the paced property. The length will be
* the same as aValues.
*/
static nsTArray<double>
GetCumulativeDistances(const nsTArray<ComputedKeyframeValues>& aValues,
nsCSSPropertyID aPacedProperty)
nsCSSPropertyID aPacedProperty,
nsStyleContext* aStyleContext)
{
// a) If aPacedProperty is a shorthand property, get its components.
// Otherwise, just add the longhand property into the set.
@ -1634,6 +1639,7 @@ GetCumulativeDistances(const nsTArray<ComputedKeyframeValues>& aValues,
prop,
prevPacedValues[propIdx].mValue,
pacedValues[propIdx].mValue,
aStyleContext,
componentDistance)) {
dist += componentDistance * componentDistance;
}
@ -1647,6 +1653,7 @@ GetCumulativeDistances(const nsTArray<ComputedKeyframeValues>& aValues,
StyleAnimationValue::ComputeDistance(aPacedProperty,
prevPacedValues[0].mValue,
pacedValues[0].mValue,
aStyleContext,
dist);
}
cumulativeDistances[i] = cumulativeDistances[preIdx] + dist;

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

@ -98,11 +98,14 @@ public:
* GetComputedKeyframeValues. Only used when |aSpacingMode| is
* SpacingMode::paced. In all other cases this parameter is unused and may
* be any value including an empty array.
* @param aStyleContext The style context used for calculating paced spacing
* on transform.
*/
static void ApplySpacing(nsTArray<Keyframe>& aKeyframes,
SpacingMode aSpacingMode,
nsCSSPropertyID aProperty,
nsTArray<ComputedKeyframeValues>& aComputedValues);
nsTArray<ComputedKeyframeValues>& aComputedValues,
nsStyleContext* aStyleContext);
/**
* Wrapper for ApplySpacing to simplify using distribute spacing.

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

@ -44,6 +44,7 @@ support-files =
mozilla/file_hide_and_show.html
mozilla/file_partial_keyframes.html
mozilla/file_spacing_property_order.html
mozilla/file_spacing_transform.html
mozilla/file_transform_limits.html
mozilla/file_underlying-discrete-value.html
mozilla/file_set-easing.html
@ -100,6 +101,7 @@ skip-if = (toolkit == 'gonk' && debug)
[mozilla/test_partial_keyframes.html]
[mozilla/test_set-easing.html]
[mozilla/test_spacing_property_order.html]
[mozilla/test_spacing_transform.html]
[mozilla/test_transform_limits.html]
[mozilla/test_underlying-discrete-value.html]
[style/test_animation-seeking-with-current-time.html]

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

@ -0,0 +1,240 @@
<!doctype html>
<meta charset=utf-8>
<script src="../testcommon.js"></script>
<body>
<script>
'use strict';
const pi = Math.PI;
const cos = Math.cos;
const sin = Math.sin;
const tan = Math.tan;
const sqrt = Math.sqrt;
// Help function for testing the computed offsets by the distance array.
function assert_animation_offsets(anim, dist) {
const epsilon = 0.00000001;
const frames = anim.effect.getKeyframes();
const cumDist = dist.reduce( (prev, curr) => {
prev.push(prev.length == 0 ? curr : curr + prev[prev.length - 1]);
return prev;
}, []);
const total = cumDist[cumDist.length - 1];
for (var i = 0; i < frames.length; ++i) {
assert_approx_equals(frames[i].computedOffset, cumDist[i] / total,
epsilon, 'computedOffset of frame ' + i);
}
}
function getAngleDist(rotate1, rotate2) {
function quaternion(axis, angle) {
var x = axis[0] * sin(angle/2.0);
var y = axis[1] * sin(angle/2.0);
var z = axis[2] * sin(angle/2.0);
var w = cos(angle/2.0);
return { 'x': x, 'y': y, 'z': z, 'w': w };
}
var q1 = quaternion(rotate1.axis, rotate1.angle);
var q2 = quaternion(rotate2.axis, rotate2.angle);
var dotProduct = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w;
return 2.0 * Math.acos(dotProduct);
}
function createMatrix(elements, Is3D) {
return (Is3D ? "matrix3d" : "matrix") + "(" + elements.join() + ")";
}
test(function(t) {
var anim = addDiv(t).animate([ { transform: "none" },
{ transform: "translate(-20px)" },
{ transform: "translate(100px)" },
{ transform: "translate(50px)"} ],
{ spacing: "paced(transform)" });
assert_animation_offsets(anim, [ 0, 20, 120, 50 ]);
}, 'Test spacing on translate' );
test(function(t) {
var anim =
addDiv(t).animate([ { transform: "none" },
{ transform: "translate3d(-20px, 10px, 100px)" },
{ transform: "translate3d(100px, 200px, 50px)" },
{ transform: "translate(50px, -10px)"} ],
{ spacing: "paced(transform)" });
var dist = [ 0,
Math.sqrt(20 * 20 + 10 * 10 + 100 * 100),
Math.sqrt(120 * 120 + 190 * 190 + 50 * 50),
Math.sqrt(50 * 50 + 210 * 210 + 50 * 50) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on translate3d' );
test(function(t) {
var anim = addDiv(t).animate([ { transform: "scale(0.5)" },
{ transform: "scale(4.5)" },
{ transform: "scale(2.5)" },
{ transform: "none"} ],
{ spacing: "paced(transform)" });
assert_animation_offsets(anim, [ 0, 4.0, 2.0, 1.5 ]);
}, 'Test spacing on scale' );
test(function(t) {
var anim = addDiv(t).animate([ { transform: "scale(0.5, 0.5)" },
{ transform: "scale3d(4.5, 5.0, 2.5)" },
{ transform: "scale3d(2.5, 1.0, 2.0)" },
{ transform: "scale3d(1, 0.5, 1.0)"} ],
{ spacing:"paced(transform)" });
var dist = [ 0,
Math.sqrt(4.0 * 4.0 + 4.5 * 4.5 + 1.5 * 1.5),
Math.sqrt(2.0 * 2.0 + 4.0 * 4.0 + 0.5 * 0.5),
Math.sqrt(1.5 * 1.5 + 0.5 * 0.5 + 1.0 * 1.0) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on scale3d' );
test(function(t) {
var anim = addDiv(t).animate([ { transform: "rotate(60deg)" },
{ transform: "none" },
{ transform: "rotate(720deg)" },
{ transform: "rotate(-360deg)"} ],
{ spacing: "paced(transform)" });
assert_animation_offsets(anim, [ 0, 60, 720, 1080 ]);
}, 'Test spacing on rotate' );
test(function(t) {
var anim = addDiv(t).animate([ { transform: "rotate3d(1,0,0,60deg)" },
{ transform: "rotate3d(1,0,0,70deg)" },
{ transform: "rotate3d(0,0,1,-110deg)" },
{ transform: "rotate3d(1,0,0,219deg)"} ],
{ spacing: "paced(transform)" });
var dist = [ 0,
getAngleDist({ axis: [1,0,0], angle: 60 * pi / 180 },
{ axis: [1,0,0], angle: 70 * pi / 180 }),
getAngleDist({ axis: [0,1,0], angle: 70 * pi / 180 },
{ axis: [0,0,1], angle: -110 * pi / 180 }),
getAngleDist({ axis: [0,0,1], angle: -110 * pi / 180 },
{ axis: [1,0,0], angle: 219 * pi / 180 }) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on rotate3d' );
test(function(t) {
var anim = addDiv(t).animate([ { transform: "skew(60deg)" },
{ transform: "none" },
{ transform: "skew(-90deg)" },
{ transform: "skew(90deg)"} ],
{ spacing: "paced(transform)" });
assert_animation_offsets(anim, [ 0, 60, 90, 180 ]);
}, 'Test spacing on skew' );
test(function(t) {
var anim = addDiv(t).animate([ { transform: "skew(60deg, 30deg)" },
{ transform: "none" },
{ transform: "skew(-90deg, 60deg)" },
{ transform: "skew(90deg, 60deg)"} ],
{ spacing: "paced(transform)" });
var dist = [ 0,
sqrt(60 * 60 + 30 * 30),
sqrt(90 * 90 + 60 * 60),
sqrt(180 * 180 + 0) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on skew along both X and Y' );
test(function(t) {
// We calculate the distance of two perspective functions by converting them
// into two matrix3ds, and then do matrix decomposition to get two
// perspective vectors, so the equivalent perspective vectors are:
// perspective 1: (0, 0, -1/128, 1);
// perspective 2: (0, 0, -1/infinity = 0, 1);
// perspective 3: (0, 0, -1/1024, 1);
// perspective 4: (0, 0, -1/32, 1);
var anim = addDiv(t).animate([ { transform: "perspective(128px)" },
{ transform: "none" },
{ transform: "perspective(1024px)" },
{ transform: "perspective(32px)"} ],
{ spacing: "paced(transform)" });
assert_animation_offsets(anim,
[ 0, 1/128, 1/1024, 1/32 - 1/1024 ]);
}, 'Test spacing on perspective' );
test(function(t) {
var anim =
addDiv(t).animate([ { transform: "none" },
{ transform: "rotate(180deg) translate(0px)" },
{ transform: "rotate(180deg) translate(1000px)" },
{ transform: "rotate(360deg) translate(1000px)"} ],
{ spacing: "paced(transform)" });
var dist = [ 0,
sqrt(pi * pi + 0),
sqrt(1000 * 1000),
sqrt(pi * pi + 0) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on matched transform lists' );
test(function(t) {
// matrix1 => translate(100px, 50px), skewX(60deg).
// matrix2 => translate(1000px), rotate(180deg).
// matrix3 => translate(1000px), scale(1.5, 0.7).
const matrix1 = createMatrix([ 1, 0, tan(pi/4.0), 1, 100, 50 ]);
const matrix2 = createMatrix([ cos(pi), sin(pi),
-sin(pi), cos(pi),
1000, 0 ]);
const matrix3 = createMatrix([ 1.5, 0, 0, 0.7, 1000, 0 ]);
var anim = addDiv(t).animate([ { transform: "none" },
{ transform: matrix1 },
{ transform: matrix2 },
{ transform: matrix3 } ],
{ spacing: "paced(transform)" });
var dist = [ 0,
sqrt(100 * 100 + 50 * 50 + pi/4 * pi/4),
sqrt(900 * 900 + 50 * 50 + pi * pi + pi/4 * pi/4),
sqrt(pi * pi + 0.5 * 0.5 + 0.3 * 0.3) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on matrix' );
test(function(t) {
// matrix1 => translate3d(100px, 50px, -10px), skew(60deg).
// matrix2 => translate3d(1000px, 0, 0), rotate3d(1, 0, 0, 180deg).
// matrix3 => translate3d(1000px, 0, 0), scale3d(1.5, 0.7, 2.2).
const matrix1 = createMatrix([ 1, 0, 0, 0,
tan(pi/4.0), 1, 0, 0,
0, 0, 1, 0,
100, 50, -10, 1 ], true);
const matrix2 = createMatrix([ 1, 0, 0, 0,
0, cos(pi), sin(pi), 0,
0, -sin(pi), cos(pi), 0,
1000, 0, 0, 1 ], true);
const matrix3 = createMatrix([ 1.5, 0, 0, 0,
0, 0.7, 0, 0,
0, 0, 2.2, 0,
1000, 0, 0, 1 ], true);
var anim = addDiv(t).animate([ { transform: "none" },
{ transform: matrix1 },
{ transform: matrix2 },
{ transform: matrix3 } ],
{ spacing: "paced(transform)" });
var dist = [ 0,
sqrt(100 * 100 + 50 * 50 + 10 * 10 + pi/4 * pi/4),
sqrt(900 * 900 + 50 * 50 + 10 * 10 + pi/4 * pi/4 + pi * pi),
sqrt(0.5 * 0.5 + 0.3 * 0.3 + 1.2 * 1.2 + pi * pi) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on matrix3d' );
test(function(t) {
var anim =
addDiv(t).animate([ { transform: "none" },
{ transform: "translate(100px, 50px) skew(45deg)" },
{ transform: "translate(1000px) " +
"rotate3d(1, 0, 0, 180deg)" },
{ transform: "translate(1000px) " +
"scale3d(2.5, 0.5, 0.7)" } ],
{ spacing: "paced(transform)" });
var dist = [ 0,
sqrt(100 * 100 + 50 * 50 + pi/4 * pi/4),
sqrt(900 * 900 + 50 * 50 + pi/4 * pi/4 + pi * pi),
sqrt(1.5 * 1.5 + 0.5 * 0.5 + 0.3 * 0.3 + pi * pi) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on mismatched transform list' );
done();
</script>
</body>

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

@ -0,0 +1,14 @@
<!doctype html>
<meta charset=utf-8>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
'use strict';
setup({explicit_done: true});
SpecialPowers.pushPrefEnv(
{ "set": [["dom.animations-api.core.enabled", true]]},
function() {
window.open("file_spacing_transform.html");
});
</script>

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

@ -53,6 +53,7 @@
#include "mozilla/Hal.h"
#include "nsISiteSpecificUserAgent.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/SSE.h"
#include "mozilla/StaticPtr.h"
#include "Connection.h"
#include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()

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

@ -2703,13 +2703,19 @@ nsDOMWindowUtils::ComputeAnimationDistance(nsIDOMElement* aElement,
"should not have shorthand");
StyleAnimationValue v1, v2;
Element* element = content->AsElement();
if (property == eCSSProperty_UNKNOWN ||
!ComputeAnimationValue(property, content->AsElement(), aValue1, v1) ||
!ComputeAnimationValue(property, content->AsElement(), aValue2, v2)) {
!ComputeAnimationValue(property, element, aValue1, v1) ||
!ComputeAnimationValue(property, element, aValue2, v2)) {
return NS_ERROR_ILLEGAL_VALUE;
}
if (!StyleAnimationValue::ComputeDistance(property, v1, v2, *aResult)) {
nsIPresShell* shell = element->GetUncomposedDoc()->GetShell();
RefPtr<nsStyleContext> styleContext = shell
? nsComputedDOMStyle::GetStyleContextForElement(element, nullptr, shell)
: nullptr;
if (!StyleAnimationValue::ComputeDistance(property, v1, v2, styleContext,
*aResult)) {
return NS_ERROR_FAILURE;
}

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

@ -4396,9 +4396,6 @@ void HTMLMediaElement::DecodeError(const MediaResult& aError)
if (mDecoder) {
ShutdownDecoder();
}
RemoveMediaElementFromURITable();
mLoadingSrc = nullptr;
mMediaSource = nullptr;
AudioTracks()->EmptyTracks();
VideoTracks()->EmptyTracks();
if (mIsLoadingFromSourceChildren) {

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

@ -31,9 +31,12 @@ LazyLogModule gCubebLog("cubeb");
void CubebLogCallback(const char* aFmt, ...)
{
char buffer[256];
va_list arglist;
va_start(arglist, aFmt);
MOZ_LOG(gCubebLog, LogLevel::Verbose, (aFmt, arglist));
VsprintfLiteral (buffer, aFmt, arglist);
MOZ_LOG(gCubebLog, LogLevel::Verbose, ("%s", buffer));
va_end(arglist);
}

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

@ -997,9 +997,6 @@ MediaDecoder::FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
mInfo = aInfo.forget();
Invalidate();
if (aEventVisibility != MediaDecoderEventVisibility::Suppressed) {
mOwner->FirstFrameLoaded();
}
// This can run cache callbacks.
mResource->EnsureCacheUpToDate();
@ -1015,6 +1012,12 @@ MediaDecoder::FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
// Run NotifySuspendedStatusChanged now to give us a chance to notice
// that autoplay should run.
NotifySuspendedStatusChanged();
// mOwner->FirstFrameLoaded() might call us back. Put it at the bottom of
// this function to avoid unexpected shutdown from reentrant calls.
if (aEventVisibility != MediaDecoderEventVisibility::Suppressed) {
mOwner->FirstFrameLoaded();
}
}
void

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

@ -229,16 +229,11 @@ protected:
MediaDecoderReaderWrapper* Reader() const { return mMaster->mReader; }
const MediaInfo& Info() const { return mMaster->Info(); }
public:
// TODO: this function is public because VisibilityChanged() calls it.
// We should handle visibility changes in state objects so this function
// can be made protected again.
//
// Note this function will delete the current state object.
// Don't access members to avoid UAF after this call.
template <class S, typename... Ts>
auto SetState(Ts&&... aArgs)
-> decltype(DeclVal<S>().Enter(Forward<Ts>(aArgs)...))
auto SetState(Ts... aArgs)
-> decltype(DeclVal<S>().Enter(Move(aArgs)...))
{
// keep mMaster in a local object because mMaster will become invalid after
// the current state object is deleted.
@ -253,16 +248,11 @@ public:
Exit();
// Note |aArgs| might reference data members of |this|. We need to keep
// |this| alive until |s->Enter()| returns.
UniquePtr<StateObject> deathGrip(master->mStateObj.release());
master->mState = s->GetState();
master->mStateObj.reset(s);
return s->Enter(Forward<Ts>(aArgs)...);
return s->Enter(Move(aArgs)...);
}
protected:
// Take a raw pointer in order not to change the life cycle of MDSM.
// It is guaranteed to be valid by MDSM.
Master* mMaster;
@ -988,6 +978,9 @@ public:
void Enter()
{
// We've decoded all samples. We don't need decoders anymore.
Reader()->ReleaseResources();
mMaster->ScheduleStateMachine();
}
@ -1291,8 +1284,7 @@ DormantState::HandleDormant(bool aDormant)
{
if (!aDormant) {
MOZ_ASSERT(!Info().IsEncrypted() || mMaster->mCDMProxy);
SeekJob seekJob = Move(mPendingSeek);
SetState<DecodingFirstFrameState>(Move(seekJob));
SetState<DecodingFirstFrameState>(Move(mPendingSeek));
}
return true;
}
@ -1301,11 +1293,10 @@ bool
MediaDecoderStateMachine::
WaitForCDMState::HandleCDMProxyReady()
{
SeekJob seekJob = Move(mPendingSeek);
if (mPendingDormant) {
SetState<DormantState>(Move(seekJob));
SetState<DormantState>(Move(mPendingSeek));
} else {
SetState<DecodingFirstFrameState>(Move(seekJob));
SetState<DecodingFirstFrameState>(Move(mPendingSeek));
}
return true;
}
@ -1366,8 +1357,7 @@ MediaDecoderStateMachine::
DecodingFirstFrameState::HandleDormant(bool aDormant)
{
if (aDormant) {
SeekJob seekJob = Move(mPendingSeek);
SetState<DormantState>(Move(seekJob));
SetState<DormantState>(Move(mPendingSeek));
}
return true;
}
@ -1386,8 +1376,7 @@ DecodingFirstFrameState::MaybeFinishDecodeFirstFrame()
mMaster->FinishDecodeFirstFrame();
if (mPendingSeek.Exists()) {
SeekJob seekJob = Move(mPendingSeek);
SetState<SeekingState>(Move(seekJob));
SetState<SeekingState>(Move(mPendingSeek));
} else {
SetState<DecodingState>();
}
@ -1497,8 +1486,7 @@ SeekingState::HandleDormant(bool aDormant)
mSeekJob.mTarget.SetType(SeekTarget::Accurate);
mSeekJob.mTarget.SetVideoOnly(false);
}
SeekJob seekJob = Move(mSeekJob);
SetState<DormantState>(Move(seekJob));
SetState<DormantState>(Move(mSeekJob));
return true;
}

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

@ -20,7 +20,11 @@ static float ExponentialInterpolate(double t0, float v0, double t1, float v1, do
static float ExponentialApproach(double t0, double v0, float v1, double timeConstant, double t)
{
return v1 + (v0 - v1) * expf(-(t - t0) / timeConstant);
if (!mozilla::dom::WebAudioUtils::FuzzyEqual(timeConstant, 0.0)) {
return v1 + (v0 - v1) * expf(-(t - t0) / timeConstant);
} else {
return v1;
}
}
static float ExtractValueFromCurve(double startTime, float* aCurve, uint32_t aCurveLength, double duration, double t)
@ -33,7 +37,15 @@ static float ExtractValueFromCurve(double startTime, float* aCurve, uint32_t aCu
if (ratio >= 1.0) {
return aCurve[aCurveLength - 1];
}
return aCurve[uint32_t(aCurveLength * ratio)];
uint32_t current = uint32_t(aCurveLength * ratio);
uint32_t next = current + 1;
if (next < aCurveLength) {
double t0 = double(current) / double(aCurveLength) * duration ;
double t1 = double(next) / double(aCurveLength) * duration ;
return LinearInterpolate(t0, aCurve[current], t1, aCurve[next], t - startTime);
} else {
return aCurve[current];
}
}
namespace mozilla {
@ -69,12 +81,6 @@ AudioEventTimeline::ValidateEvent(AudioTimelineEvent& aEvent,
}
}
if (aEvent.mType == AudioTimelineEvent::SetTarget &&
WebAudioUtils::FuzzyEqual(aEvent.mTimeConstant, 0.0)) {
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
return false;
}
bool timeAndValueValid = IsValid(aEvent.mValue) &&
IsValid(aEvent.mDuration);
if (!timeAndValueValid) {

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

@ -403,7 +403,7 @@ void TestSetTargetZeroTimeConstant()
ErrorResultMock rv;
timeline.SetTargetAtTime(20.0f, 1.0, 0.0, rv);
is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned");
is(timeline.GetValueAtTime(1.0), 20.0f, "Should get the correct value when t0 == t1");
}
void TestExponentialInvalidPreviousZeroValue()

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

@ -66,6 +66,7 @@ tags=capturestream
[test_audioParamSetCurveAtTimeTwice.html]
[test_audioParamSetCurveAtTimeZeroDuration.html]
[test_audioParamSetTargetAtTime.html]
[test_audioParamSetTargetAtTimeZeroTimeConstant.html]
[test_audioParamSetValueAtTime.html]
[test_audioParamTimelineDestinationOffset.html]
[test_badConnect.html]

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

@ -16,17 +16,10 @@ var gTest = {
length: 2048,
numberOfChannels: 1,
createGraph: function(context) {
var sourceBuffer = context.createBuffer(1, 2048, context.sampleRate);
for (var i = 0; i < 2048; ++i) {
sourceBuffer.getChannelData(0)[i] = 1;
}
var source = context.createBufferSource();
source.buffer = sourceBuffer;
var source = context.createConstantSource();
var gain = context.createGain();
gain.gain.setValueCurveAtTime(this.curve, T0, this.duration);
source.connect(gain);
source.start(0);
@ -34,14 +27,19 @@ var gTest = {
},
createExpectedBuffers: function(context) {
this.duration = 1024 / context.sampleRate;
this.curve = new Float32Array(100);
for (var i = 0; i < 100; ++i) {
this.curve[i] = Math.sin(440 * 2 * Math.PI * i / context.sampleRate);
}
this.curve = new Float32Array([1.0, 0.5, 0.75, 0.25]);
var expectedBuffer = context.createBuffer(1, 2048, context.sampleRate);
var data = expectedBuffer.getChannelData(0);
for (var i = 0; i < 2048; ++i) {
var t = i / context.sampleRate;
expectedBuffer.getChannelData(0)[i] = this.curve[Math.min(99, Math.floor(100 * Math.min(1.0, (t - T0) / this.duration)))];
if (i < 256) {
data[i] = 1.0 - 0.5*i/256;
} else if (i < 512) {
data[i] = 0.5 + 0.25*(i - 256)/256;
} else if (i < 768) {
data[i] = 0.75 - 0.5*(i - 512)/256;
} else {
data[i] = 0.25;
}
}
return expectedBuffer;
},

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

@ -1,7 +1,7 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test AudioParam.linearRampToValue</title>
<title>Test AudioParam.setValueCurveAtTime twice</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="webaudio.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
@ -10,28 +10,28 @@
<pre id="test">
<script class="testbody" type="text/javascript">
function linearInterpolate(t0, v0, t1, v1, t)
{
return v0 + (v1 - v0) * ((t - t0) / (t1 - t0));
}
var T0 = 0;
var gTest = {
length: 2048,
numberOfChannels: 1,
createGraph: function(context) {
var sourceBuffer = context.createBuffer(1, 2048, context.sampleRate);
for (var i = 0; i < 2048; ++i) {
sourceBuffer.getChannelData(0)[i] = 1;
}
var curve2 = new Float32Array(100);
for (var i = 0; i < 100; ++i) {
curve2[i] = Math.sin(220 * 6 * Math.PI * i / context.sampleRate);
}
var source = context.createBufferSource();
source.buffer = sourceBuffer;
var source = context.createConstantSource();
var gain = context.createGain();
gain.gain.setValueCurveAtTime(curve2, T0, this.duration/2);
//Set a diffrent curve from the first one
//Set a different curve from the first one
gain.gain.setValueCurveAtTime(this.curve, T0, this.duration);
source.connect(gain);
@ -48,7 +48,15 @@ var gTest = {
var expectedBuffer = context.createBuffer(1, 2048, context.sampleRate);
for (var i = 0; i < 2048; ++i) {
var t = i / context.sampleRate;
expectedBuffer.getChannelData(0)[i] = this.curve[Math.min(99, Math.floor(100 * Math.min(1.0, (t - T0) / this.duration)))];
var current = Math.min(99, Math.floor(100 * Math.min(1.0, (t - T0) / this.duration)));
var next = current + 1;
if (next < this.curve.length) {
var t0 = current / this.curve.length * this.duration;
var t1 = next / this.curve.length * this.duration;
expectedBuffer.getChannelData(0)[i] = linearInterpolate(t0, this.curve[current], t1, this.curve[next], t);
} else {
expectedBuffer.getChannelData(0)[i] = this.curve[current];
}
}
return expectedBuffer;
},

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

@ -0,0 +1,55 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test AudioParam.setTargetAtTime with zero time constant</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="webaudio.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
var V0 = 0.9;
var V1 = 0.1;
var T0 = 0;
var TimeConstant = 0;
var gTest = {
length: 2048,
numberOfChannels: 1,
createGraph: function(context) {
var sourceBuffer = context.createBuffer(1, 2048, context.sampleRate);
for (var i = 0; i < 2048; ++i) {
sourceBuffer.getChannelData(0)[i] = 1;
}
var source = context.createBufferSource();
source.buffer = sourceBuffer;
var gain = context.createGain();
gain.gain.value = V0;
gain.gain.setTargetAtTime(V1, T0, TimeConstant);
source.connect(gain);
source.start(0);
return gain;
},
createExpectedBuffers: function(context) {
var T1 = 2048 / context.sampleRate;
var expectedBuffer = context.createBuffer(1, 2048, context.sampleRate);
for (var i = 0; i < 2048; ++i) {
var t = i / context.sampleRate;
expectedBuffer.getChannelData(0)[i] = V1;
}
return expectedBuffer;
},
};
runTest();
</script>
</pre>
</body>
</html>

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

@ -278,6 +278,7 @@ nsSMILCSSValueType::ComputeDistance(const nsSMILValue& aFrom,
return StyleAnimationValue::ComputeDistance(toWrapper->mPropID,
*fromCSSValue, *toCSSValue,
nullptr,
aDistance) ?
NS_OK : NS_ERROR_FAILURE;
}

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

@ -21,7 +21,6 @@ dictionary RTCIceServer {
};
enum RTCIceTransportPolicy {
"none",
"relay",
"all"
};

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

@ -150,8 +150,8 @@ ChangeStyleTransaction::DoTransaction()
nsGkAtoms::style);
nsAutoString values;
nsresult result = cssDecl->GetPropertyValue(propertyNameString, values);
NS_ENSURE_SUCCESS(result, result);
nsresult rv = cssDecl->GetPropertyValue(propertyNameString, values);
NS_ENSURE_SUCCESS(rv, rv);
mUndoValue.Assign(values);
// Does this property accept more than one value? (bug 62682)
@ -168,18 +168,17 @@ ChangeStyleTransaction::DoTransaction()
RemoveValueFromListOfValues(values, NS_LITERAL_STRING("none"));
RemoveValueFromListOfValues(values, mValue);
if (values.IsEmpty()) {
result = cssDecl->RemoveProperty(propertyNameString, returnString);
NS_ENSURE_SUCCESS(result, result);
rv = cssDecl->RemoveProperty(propertyNameString, returnString);
NS_ENSURE_SUCCESS(rv, rv);
} else {
nsAutoString priority;
cssDecl->GetPropertyPriority(propertyNameString, priority);
result = cssDecl->SetProperty(propertyNameString, values,
priority);
NS_ENSURE_SUCCESS(result, result);
rv = cssDecl->SetProperty(propertyNameString, values, priority);
NS_ENSURE_SUCCESS(rv, rv);
}
} else {
result = cssDecl->RemoveProperty(propertyNameString, returnString);
NS_ENSURE_SUCCESS(result, result);
rv = cssDecl->RemoveProperty(propertyNameString, returnString);
NS_ENSURE_SUCCESS(rv, rv);
}
} else {
nsAutoString priority;
@ -194,18 +193,17 @@ ChangeStyleTransaction::DoTransaction()
} else {
values.Assign(mValue);
}
result = cssDecl->SetProperty(propertyNameString, values,
priority);
NS_ENSURE_SUCCESS(result, result);
rv = cssDecl->SetProperty(propertyNameString, values, priority);
NS_ENSURE_SUCCESS(rv, rv);
}
// Let's be sure we don't keep an empty style attribute
uint32_t length;
result = cssDecl->GetLength(&length);
NS_ENSURE_SUCCESS(result, result);
rv = cssDecl->GetLength(&length);
NS_ENSURE_SUCCESS(rv, rv);
if (!length) {
result = mElement->UnsetAttr(kNameSpaceID_None, nsGkAtoms::style, true);
NS_ENSURE_SUCCESS(result, result);
rv = mElement->UnsetAttr(kNameSpaceID_None, nsGkAtoms::style, true);
NS_ENSURE_SUCCESS(rv, rv);
} else {
mRedoAttributeWasSet = true;
}
@ -217,7 +215,6 @@ nsresult
ChangeStyleTransaction::SetStyle(bool aAttributeWasSet,
nsAString& aValue)
{
nsresult result = NS_OK;
if (aAttributeWasSet) {
// The style attribute was not empty, let's recreate the declaration
nsAutoString propertyNameString;
@ -230,18 +227,14 @@ ChangeStyleTransaction::SetStyle(bool aAttributeWasSet,
if (aValue.IsEmpty()) {
// An empty value means we have to remove the property
nsAutoString returnString;
result = cssDecl->RemoveProperty(propertyNameString, returnString);
} else {
// Let's recreate the declaration as it was
nsAutoString priority;
cssDecl->GetPropertyPriority(propertyNameString, priority);
result = cssDecl->SetProperty(propertyNameString, aValue, priority);
return cssDecl->RemoveProperty(propertyNameString, returnString);
}
} else {
result = mElement->UnsetAttr(kNameSpaceID_None, nsGkAtoms::style, true);
// Let's recreate the declaration as it was
nsAutoString priority;
cssDecl->GetPropertyPriority(propertyNameString, priority);
return cssDecl->SetProperty(propertyNameString, aValue, priority);
}
return result;
return mElement->UnsetAttr(kNameSpaceID_None, nsGkAtoms::style, true);
}
NS_IMETHODIMP

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

@ -33,53 +33,53 @@ NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
NS_IMETHODIMP
EditAggregateTransaction::DoTransaction()
{
nsresult result=NS_OK; // it's legal (but not very useful) to have an empty child list
// FYI: It's legal (but not very useful) to have an empty child list.
for (uint32_t i = 0, length = mChildren.Length(); i < length; ++i) {
nsITransaction *txn = mChildren[i];
if (!txn) {
return NS_ERROR_NULL_POINTER;
}
result = txn->DoTransaction();
if (NS_FAILED(result)) {
break;
nsresult rv = txn->DoTransaction();
if (NS_FAILED(rv)) {
return rv;
}
}
return result;
return NS_OK;
}
NS_IMETHODIMP
EditAggregateTransaction::UndoTransaction()
{
nsresult result=NS_OK; // it's legal (but not very useful) to have an empty child list
// undo goes through children backwards
// FYI: It's legal (but not very useful) to have an empty child list.
// Undo goes through children backwards.
for (uint32_t i = mChildren.Length(); i--; ) {
nsITransaction *txn = mChildren[i];
if (!txn) {
return NS_ERROR_NULL_POINTER;
}
result = txn->UndoTransaction();
if (NS_FAILED(result)) {
break;
nsresult rv = txn->UndoTransaction();
if (NS_FAILED(rv)) {
return rv;
}
}
return result;
return NS_OK;
}
NS_IMETHODIMP
EditAggregateTransaction::RedoTransaction()
{
nsresult result=NS_OK; // it's legal (but not very useful) to have an empty child list
// It's legal (but not very useful) to have an empty child list.
for (uint32_t i = 0, length = mChildren.Length(); i < length; ++i) {
nsITransaction *txn = mChildren[i];
if (!txn) {
return NS_ERROR_NULL_POINTER;
}
result = txn->RedoTransaction();
if (NS_FAILED(result)) {
break;
nsresult rv = txn->RedoTransaction();
if (NS_FAILED(rv)) {
return rv;
}
}
return result;
return NS_OK;
}
NS_IMETHODIMP

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

@ -1451,14 +1451,14 @@ EditorBase::SplitNode(nsIContent& aNode,
mRangeUpdater.SelAdjSplitNode(aNode, aOffset, newNode);
nsresult result = aResult.StealNSResult();
nsresult rv = aResult.StealNSResult();
for (auto& listener : mActionListeners) {
listener->DidSplitNode(aNode.AsDOMNode(), aOffset, GetAsDOMNode(newNode),
result);
rv);
}
// Note: result might be a success code, so we can't use Throw() to
// set it on aResult.
aResult = result;
aResult = rv;
return newNode;
}
@ -1495,11 +1495,11 @@ EditorBase::JoinNodes(nsINode& aLeftNode,
parent->AsDOMNode());
}
nsresult result = NS_OK;
nsresult rv = NS_OK;
RefPtr<JoinNodeTransaction> transaction =
CreateTxnForJoinNode(aLeftNode, aRightNode);
if (transaction) {
result = DoTransaction(transaction);
rv = DoTransaction(transaction);
}
mRangeUpdater.SelAdjJoinNodes(aLeftNode, aRightNode, *parent, offset,
@ -1507,10 +1507,10 @@ EditorBase::JoinNodes(nsINode& aLeftNode,
for (auto& listener : mActionListeners) {
listener->DidJoinNodes(aLeftNode.AsDOMNode(), aRightNode.AsDOMNode(),
parent->AsDOMNode(), result);
parent->AsDOMNode(), rv);
}
return result;
return rv;
}
NS_IMETHODIMP

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

@ -258,16 +258,16 @@ HTMLEditor::Init(nsIDOMDocument* aDoc,
NS_ENSURE_TRUE(aDoc, NS_ERROR_NULL_POINTER);
MOZ_ASSERT(aInitialValue.IsEmpty(), "Non-empty initial values not supported");
nsresult result = NS_OK, rulesRes = NS_OK;
nsresult rulesRv = NS_OK;
{
// block to scope AutoEditInitRulesTrigger
AutoEditInitRulesTrigger rulesTrigger(this, rulesRes);
AutoEditInitRulesTrigger rulesTrigger(this, rulesRv);
// Init the plaintext editor
result = TextEditor::Init(aDoc, aRoot, nullptr, aFlags, aInitialValue);
if (NS_FAILED(result)) {
return result;
nsresult rv = TextEditor::Init(aDoc, aRoot, nullptr, aFlags, aInitialValue);
if (NS_FAILED(rv)) {
return rv;
}
// Init mutation observer
@ -317,9 +317,9 @@ HTMLEditor::Init(nsIDOMDocument* aDoc,
}
}
}
NS_ENSURE_SUCCESS(rulesRv, rulesRv);
NS_ENSURE_SUCCESS(rulesRes, rulesRes);
return result;
return NS_OK;
}
NS_IMETHODIMP
@ -1553,8 +1553,8 @@ HTMLEditor::InsertElementAtSelection(nsIDOMElement* aElement,
NS_ENSURE_SUCCESS(rv, rv);
}
nsresult result = DeleteSelectionAndPrepareToCreateNode();
NS_ENSURE_SUCCESS(result, result);
nsresult rv = DeleteSelectionAndPrepareToCreateNode();
NS_ENSURE_SUCCESS(rv, rv);
}
// If deleting, selection will be collapsed.
@ -3637,7 +3637,6 @@ HTMLEditor::IsTextPropertySetByContent(nsIDOMNode* aNode,
bool& aIsSet,
nsAString* outValue)
{
nsresult result;
aIsSet = false; // must be initialized to false for code below to work
nsAutoString propName;
aProperty->ToString(propName);
@ -3680,8 +3679,7 @@ HTMLEditor::IsTextPropertySetByContent(nsIDOMNode* aNode,
}
}
nsCOMPtr<nsIDOMNode>temp;
result = node->GetParentNode(getter_AddRefs(temp));
if (NS_SUCCEEDED(result) && temp) {
if (NS_SUCCEEDED(node->GetParentNode(getter_AddRefs(temp))) && temp) {
node = temp;
} else {
node = nullptr;
@ -3760,10 +3758,10 @@ HTMLEditor::CollapseAdjacentTextNodes(nsRange* aInRange)
// build a list of editable text nodes
nsresult result;
nsresult rv = NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIContentIterator> iter =
do_CreateInstance("@mozilla.org/content/subtree-content-iterator;1", &result);
NS_ENSURE_SUCCESS(result, result);
do_CreateInstance("@mozilla.org/content/subtree-content-iterator;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
iter->Init(aInRange);
@ -3788,22 +3786,21 @@ HTMLEditor::CollapseAdjacentTextNodes(nsRange* aInRange)
// get the prev sibling of the right node, and see if its leftTextNode
nsCOMPtr<nsIDOMNode> prevSibOfRightNode;
result =
rightTextNode->GetPreviousSibling(getter_AddRefs(prevSibOfRightNode));
NS_ENSURE_SUCCESS(result, result);
rv = rightTextNode->GetPreviousSibling(getter_AddRefs(prevSibOfRightNode));
NS_ENSURE_SUCCESS(rv, rv);
if (prevSibOfRightNode && prevSibOfRightNode == leftTextNode) {
nsCOMPtr<nsIDOMNode> parent;
result = rightTextNode->GetParentNode(getter_AddRefs(parent));
NS_ENSURE_SUCCESS(result, result);
rv = rightTextNode->GetParentNode(getter_AddRefs(parent));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(parent, NS_ERROR_NULL_POINTER);
result = JoinNodes(leftTextNode, rightTextNode, parent);
NS_ENSURE_SUCCESS(result, result);
rv = JoinNodes(leftTextNode, rightTextNode, parent);
NS_ENSURE_SUCCESS(rv, rv);
}
textNodes.RemoveElementAt(0); // remove the leftmost text node from the list
}
return result;
return NS_OK;
}
nsresult

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

@ -346,8 +346,8 @@ RangeUpdater::SelAdjSplitNode(nsIContent& aOldRightNode,
int32_t offset = parent ? parent->IndexOf(&aOldRightNode) : -1;
// first part is same as inserting aNewLeftnode
nsresult result = SelAdjInsertNode(parent, offset - 1);
NS_ENSURE_SUCCESS(result, result);
nsresult rv = SelAdjInsertNode(parent, offset - 1);
NS_ENSURE_SUCCESS(rv, rv);
// next step is to check for range enpoints inside aOldRightNode
for (size_t i = 0; i < count; i++) {

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

@ -565,8 +565,6 @@ nsresult
TextEditor::ExtendSelectionForDelete(Selection* aSelection,
nsIEditor::EDirection* aAction)
{
nsresult result = NS_OK;
bool bCollapsed = aSelection->Collapsed();
if (*aAction == eNextWord ||
@ -579,19 +577,20 @@ TextEditor::ExtendSelectionForDelete(Selection* aSelection,
GetSelectionController(getter_AddRefs(selCont));
NS_ENSURE_TRUE(selCont, NS_ERROR_NO_INTERFACE);
nsresult rv;
switch (*aAction) {
case eNextWord:
result = selCont->WordExtendForDelete(true);
rv = selCont->WordExtendForDelete(true);
// DeleteSelectionImpl doesn't handle these actions
// because it's inside batching, so don't confuse it:
*aAction = eNone;
break;
case ePreviousWord:
result = selCont->WordExtendForDelete(false);
rv = selCont->WordExtendForDelete(false);
*aAction = eNone;
break;
case eNext:
result = selCont->CharacterExtendForDelete();
rv = selCont->CharacterExtendForDelete();
// Don't set aAction to eNone (see Bug 502259)
break;
case ePrevious: {
@ -602,8 +601,8 @@ TextEditor::ExtendSelectionForDelete(Selection* aSelection,
// typed character.
nsCOMPtr<nsIDOMNode> node;
int32_t offset;
result = GetStartNodeAndOffset(aSelection, getter_AddRefs(node), &offset);
NS_ENSURE_SUCCESS(result, result);
rv = GetStartNodeAndOffset(aSelection, getter_AddRefs(node), &offset);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
// node might be anonymous DIV, so we find better text node
@ -613,15 +612,15 @@ TextEditor::ExtendSelectionForDelete(Selection* aSelection,
nsCOMPtr<nsIDOMCharacterData> charData = do_QueryInterface(node);
if (charData) {
nsAutoString data;
result = charData->GetData(data);
NS_ENSURE_SUCCESS(result, result);
rv = charData->GetData(data);
NS_ENSURE_SUCCESS(rv, rv);
if ((offset > 1 &&
NS_IS_LOW_SURROGATE(data[offset - 1]) &&
NS_IS_HIGH_SURROGATE(data[offset - 2])) ||
(offset > 0 &&
gfxFontUtils::IsVarSelector(data[offset - 1]))) {
result = selCont->CharacterExtendForBackspace();
rv = selCont->CharacterExtendForBackspace();
}
}
}
@ -629,19 +628,20 @@ TextEditor::ExtendSelectionForDelete(Selection* aSelection,
}
case eToBeginningOfLine:
selCont->IntraLineMove(true, false); // try to move to end
result = selCont->IntraLineMove(false, true); // select to beginning
rv = selCont->IntraLineMove(false, true); // select to beginning
*aAction = eNone;
break;
case eToEndOfLine:
result = selCont->IntraLineMove(true, true);
rv = selCont->IntraLineMove(true, true);
*aAction = eNext;
break;
default: // avoid several compiler warnings
result = NS_OK;
rv = NS_OK;
break;
}
return rv;
}
return result;
return NS_OK;
}
nsresult
@ -657,8 +657,6 @@ TextEditor::DeleteSelection(EDirection aAction,
// Protect the edit rules object from dying
nsCOMPtr<nsIEditRules> rules(mRules);
nsresult result;
// delete placeholder txns merge.
AutoPlaceHolderBatch batch(this, nsGkAtoms::DeleteTxnName);
AutoRules beginRulesSniffing(this, EditAction::deleteSelection, aAction);
@ -676,8 +674,8 @@ TextEditor::DeleteSelection(EDirection aAction,
(aAction == eNextWord || aAction == ePreviousWord ||
aAction == eToBeginningOfLine || aAction == eToEndOfLine)) {
if (mCaretStyle == 1) {
result = selection->CollapseToStart();
NS_ENSURE_SUCCESS(result, result);
nsresult rv = selection->CollapseToStart();
NS_ENSURE_SUCCESS(rv, rv);
} else {
aAction = eNone;
}
@ -687,17 +685,16 @@ TextEditor::DeleteSelection(EDirection aAction,
ruleInfo.collapsedAction = aAction;
ruleInfo.stripWrappers = aStripWrappers;
bool cancel, handled;
result = rules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
NS_ENSURE_SUCCESS(result, result);
nsresult rv = rules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
NS_ENSURE_SUCCESS(rv, rv);
if (!cancel && !handled) {
result = DeleteSelectionImpl(aAction, aStripWrappers);
rv = DeleteSelectionImpl(aAction, aStripWrappers);
}
if (!cancel) {
// post-process
result = rules->DidDoAction(selection, &ruleInfo, result);
rv = rules->DidDoAction(selection, &ruleInfo, rv);
}
return result;
return rv;
}
NS_IMETHODIMP
@ -1091,15 +1088,15 @@ TextEditor::Undo(uint32_t aCount)
TextRulesInfo ruleInfo(EditAction::undo);
RefPtr<Selection> selection = GetSelection();
bool cancel, handled;
nsresult result = rules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
nsresult rv = rules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
if (!cancel && NS_SUCCEEDED(result)) {
result = EditorBase::Undo(aCount);
result = rules->DidDoAction(selection, &ruleInfo, result);
if (!cancel && NS_SUCCEEDED(rv)) {
rv = EditorBase::Undo(aCount);
rv = rules->DidDoAction(selection, &ruleInfo, rv);
}
NotifyEditorObservers(eNotifyEditorObserversOfEnd);
return result;
return rv;
}
NS_IMETHODIMP
@ -1119,15 +1116,15 @@ TextEditor::Redo(uint32_t aCount)
TextRulesInfo ruleInfo(EditAction::redo);
RefPtr<Selection> selection = GetSelection();
bool cancel, handled;
nsresult result = rules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
nsresult rv = rules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
if (!cancel && NS_SUCCEEDED(result)) {
result = EditorBase::Redo(aCount);
result = rules->DidDoAction(selection, &ruleInfo, result);
if (!cancel && NS_SUCCEEDED(rv)) {
rv = EditorBase::Redo(aCount);
rv = rules->DidDoAction(selection, &ruleInfo, rv);
}
NotifyEditorObservers(eNotifyEditorObserversOfEnd);
return result;
return rv;
}
bool

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

@ -48,110 +48,112 @@ void TextEditorTest::Run(nsIEditor *aEditor, int32_t *outNumTests, int32_t *outN
nsresult TextEditorTest::RunUnitTest(int32_t *outNumTests, int32_t *outNumTestsFailed)
{
nsresult result;
NS_ENSURE_TRUE(outNumTests && outNumTestsFailed, NS_ERROR_NULL_POINTER);
*outNumTests = 0;
*outNumTestsFailed = 0;
result = InitDoc();
TEST_RESULT(result);
nsresult rv = InitDoc();
TEST_RESULT(rv);
// shouldn't we just bail on error here?
// insert some simple text
result = mTextEditor->InsertText(NS_LITERAL_STRING("1234567890abcdefghij1234567890"));
TEST_RESULT(result);
rv = mTextEditor->InsertText(NS_LITERAL_STRING("1234567890abcdefghij1234567890"));
TEST_RESULT(rv);
(*outNumTests)++;
if (NS_FAILED(result))
if (NS_FAILED(rv)) {
++(*outNumTestsFailed);
}
// insert some more text
result = mTextEditor->InsertText(NS_LITERAL_STRING("Moreover, I am cognizant of the interrelatedness of all communities and states. I cannot sit idly by in Atlanta and not be concerned about what happens in Birmingham. Injustice anywhere is a threat to justice everywhere"));
TEST_RESULT(result);
rv = mTextEditor->InsertText(NS_LITERAL_STRING("Moreover, I am cognizant of the interrelatedness of all communities and states. I cannot sit idly by in Atlanta and not be concerned about what happens in Birmingham. Injustice anywhere is a threat to justice everywhere"));
TEST_RESULT(rv);
(*outNumTests)++;
if (NS_FAILED(result))
if (NS_FAILED(rv)) {
++(*outNumTestsFailed);
}
result = TestInsertBreak();
TEST_RESULT(result);
rv = TestInsertBreak();
TEST_RESULT(rv);
(*outNumTests)++;
if (NS_FAILED(result))
if (NS_FAILED(rv)) {
++(*outNumTestsFailed);
}
result = TestTextProperties();
TEST_RESULT(result);
rv = TestTextProperties();
TEST_RESULT(rv);
(*outNumTests)++;
if (NS_FAILED(result))
if (NS_FAILED(rv)) {
++(*outNumTestsFailed);
}
// get us back to the original document
result = mEditor->Undo(12);
TEST_RESULT(result);
rv = mEditor->Undo(12);
TEST_RESULT(rv);
return result;
return rv;
}
nsresult TextEditorTest::InitDoc()
{
nsresult result = mEditor->SelectAll();
TEST_RESULT(result);
result = mEditor->DeleteSelection(nsIEditor::eNext, nsIEditor::eStrip);
TEST_RESULT(result);
return result;
nsresult rv = mEditor->SelectAll();
TEST_RESULT(rv);
rv = mEditor->DeleteSelection(nsIEditor::eNext, nsIEditor::eStrip);
TEST_RESULT(rv);
return rv;
}
nsresult TextEditorTest::TestInsertBreak()
{
nsCOMPtr<nsISelection>selection;
nsresult result = mEditor->GetSelection(getter_AddRefs(selection));
TEST_RESULT(result);
nsresult rv = mEditor->GetSelection(getter_AddRefs(selection));
TEST_RESULT(rv);
TEST_POINTER(selection.get());
nsCOMPtr<nsIDOMNode>anchor;
result = selection->GetAnchorNode(getter_AddRefs(anchor));
TEST_RESULT(result);
rv = selection->GetAnchorNode(getter_AddRefs(anchor));
TEST_RESULT(rv);
TEST_POINTER(anchor.get());
selection->Collapse(anchor, 0);
// insert one break
printf("inserting a break\n");
result = mTextEditor->InsertLineBreak();
TEST_RESULT(result);
rv = mTextEditor->InsertLineBreak();
TEST_RESULT(rv);
mEditor->DebugDumpContent();
// insert a second break adjacent to the first
printf("inserting a second break\n");
result = mTextEditor->InsertLineBreak();
TEST_RESULT(result);
rv = mTextEditor->InsertLineBreak();
TEST_RESULT(rv);
mEditor->DebugDumpContent();
return result;
return rv;
}
nsresult TextEditorTest::TestTextProperties()
{
nsCOMPtr<nsIDOMDocument>doc;
nsresult result = mEditor->GetDocument(getter_AddRefs(doc));
TEST_RESULT(result);
nsresult rv = mEditor->GetDocument(getter_AddRefs(doc));
TEST_RESULT(rv);
TEST_POINTER(doc.get());
nsCOMPtr<nsIDOMNodeList>nodeList;
// XXX This is broken, text nodes are not elements.
nsAutoString textTag(NS_LITERAL_STRING("#text"));
result = doc->GetElementsByTagName(textTag, getter_AddRefs(nodeList));
TEST_RESULT(result);
rv = doc->GetElementsByTagName(textTag, getter_AddRefs(nodeList));
TEST_RESULT(rv);
TEST_POINTER(nodeList.get());
uint32_t count;
nodeList->GetLength(&count);
NS_ASSERTION(0!=count, "there are no text nodes in the document!");
nsCOMPtr<nsIDOMNode>textNode;
result = nodeList->Item(count-1, getter_AddRefs(textNode));
TEST_RESULT(result);
rv = nodeList->Item(count - 1, getter_AddRefs(textNode));
TEST_RESULT(rv);
TEST_POINTER(textNode.get());
// set the whole text node to bold
printf("set the whole first text node to bold\n");
nsCOMPtr<nsISelection>selection;
result = mEditor->GetSelection(getter_AddRefs(selection));
TEST_RESULT(result);
rv = mEditor->GetSelection(getter_AddRefs(selection));
TEST_RESULT(rv);
TEST_POINTER(selection.get());
nsCOMPtr<nsIDOMCharacterData>textData;
textData = do_QueryInterface(textNode);
@ -169,17 +171,17 @@ nsresult TextEditorTest::TestTextProperties()
const nsAFlatString& empty = EmptyString();
result = htmlEditor->GetInlineProperty(nsGkAtoms::b, empty, empty, &first,
&any, &all);
TEST_RESULT(result);
rv = htmlEditor->GetInlineProperty(nsGkAtoms::b, empty, empty, &first,
&any, &all);
TEST_RESULT(rv);
NS_ASSERTION(false==first, "first should be false");
NS_ASSERTION(false==any, "any should be false");
NS_ASSERTION(false==all, "all should be false");
result = htmlEditor->SetInlineProperty(nsGkAtoms::b, empty, empty);
TEST_RESULT(result);
result = htmlEditor->GetInlineProperty(nsGkAtoms::b, empty, empty, &first,
&any, &all);
TEST_RESULT(result);
rv = htmlEditor->SetInlineProperty(nsGkAtoms::b, empty, empty);
TEST_RESULT(rv);
rv = htmlEditor->GetInlineProperty(nsGkAtoms::b, empty, empty, &first,
&any, &all);
TEST_RESULT(rv);
NS_ASSERTION(true==first, "first should be true");
NS_ASSERTION(true==any, "any should be true");
NS_ASSERTION(true==all, "all should be true");
@ -187,11 +189,11 @@ nsresult TextEditorTest::TestTextProperties()
// remove the bold we just set
printf("set the whole first text node to not bold\n");
result = htmlEditor->RemoveInlineProperty(nsGkAtoms::b, empty);
TEST_RESULT(result);
result = htmlEditor->GetInlineProperty(nsGkAtoms::b, empty, empty, &first,
&any, &all);
TEST_RESULT(result);
rv = htmlEditor->RemoveInlineProperty(nsGkAtoms::b, empty);
TEST_RESULT(rv);
rv = htmlEditor->GetInlineProperty(nsGkAtoms::b, empty, empty, &first,
&any, &all);
TEST_RESULT(rv);
NS_ASSERTION(false==first, "first should be false");
NS_ASSERTION(false==any, "any should be false");
NS_ASSERTION(false==all, "all should be false");
@ -201,61 +203,57 @@ nsresult TextEditorTest::TestTextProperties()
printf("set the first text node (1, length-1) to bold and italic, and (2, length-1) to underline.\n");
selection->Collapse(textNode, 1);
selection->Extend(textNode, length-1);
result = htmlEditor->SetInlineProperty(nsGkAtoms::b, empty, empty);
TEST_RESULT(result);
result = htmlEditor->GetInlineProperty(nsGkAtoms::b, empty, empty, &first,
&any, &all);
TEST_RESULT(result);
rv = htmlEditor->SetInlineProperty(nsGkAtoms::b, empty, empty);
TEST_RESULT(rv);
rv = htmlEditor->GetInlineProperty(nsGkAtoms::b, empty, empty, &first,
&any, &all);
TEST_RESULT(rv);
NS_ASSERTION(true==first, "first should be true");
NS_ASSERTION(true==any, "any should be true");
NS_ASSERTION(true==all, "all should be true");
mEditor->DebugDumpContent();
// make all that same text italic
result = htmlEditor->SetInlineProperty(nsGkAtoms::i, empty, empty);
TEST_RESULT(result);
result = htmlEditor->GetInlineProperty(nsGkAtoms::i, empty, empty, &first,
&any, &all);
TEST_RESULT(result);
rv = htmlEditor->SetInlineProperty(nsGkAtoms::i, empty, empty);
TEST_RESULT(rv);
rv = htmlEditor->GetInlineProperty(nsGkAtoms::i, empty, empty, &first,
&any, &all);
TEST_RESULT(rv);
NS_ASSERTION(true==first, "first should be true");
NS_ASSERTION(true==any, "any should be true");
NS_ASSERTION(true==all, "all should be true");
result = htmlEditor->GetInlineProperty(nsGkAtoms::b, empty, empty, &first,
&any, &all);
TEST_RESULT(result);
rv = htmlEditor->GetInlineProperty(nsGkAtoms::b, empty, empty, &first,
&any, &all);
TEST_RESULT(rv);
NS_ASSERTION(true==first, "first should be true");
NS_ASSERTION(true==any, "any should be true");
NS_ASSERTION(true==all, "all should be true");
mEditor->DebugDumpContent();
// make all the text underlined, except for the first 2 and last 2 characters
result = doc->GetElementsByTagName(textTag, getter_AddRefs(nodeList));
TEST_RESULT(result);
rv = doc->GetElementsByTagName(textTag, getter_AddRefs(nodeList));
TEST_RESULT(rv);
TEST_POINTER(nodeList.get());
nodeList->GetLength(&count);
NS_ASSERTION(0!=count, "there are no text nodes in the document!");
result = nodeList->Item(count-2, getter_AddRefs(textNode));
TEST_RESULT(result);
rv = nodeList->Item(count-2, getter_AddRefs(textNode));
TEST_RESULT(rv);
TEST_POINTER(textNode.get());
textData = do_QueryInterface(textNode);
textData->GetLength(&length);
NS_ASSERTION(length==915, "wrong text node");
selection->Collapse(textNode, 1);
selection->Extend(textNode, length-2);
result = htmlEditor->SetInlineProperty(nsGkAtoms::u, empty, empty);
TEST_RESULT(result);
result = htmlEditor->GetInlineProperty(nsGkAtoms::u, empty, empty, &first,
&any, &all);
TEST_RESULT(result);
rv = htmlEditor->SetInlineProperty(nsGkAtoms::u, empty, empty);
TEST_RESULT(rv);
rv = htmlEditor->GetInlineProperty(nsGkAtoms::u, empty, empty, &first,
&any, &all);
TEST_RESULT(rv);
NS_ASSERTION(true==first, "first should be true");
NS_ASSERTION(true==any, "any should be true");
NS_ASSERTION(true==all, "all should be true");
mEditor->DebugDumpContent();
return result;
return rv;
}
#endif

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

@ -93,11 +93,11 @@ TypeInState::NotifySelectionChanged(nsIDOMDocument* aDOMDocument,
nsCOMPtr<nsIDOMNode> selNode;
int32_t selOffset = 0;
nsresult result =
nsresult rv =
EditorBase::GetStartNodeAndOffset(selection, getter_AddRefs(selNode),
&selOffset);
NS_ENSURE_SUCCESS(result, result);
NS_ENSURE_SUCCESS(rv, rv);
if (selNode &&
selNode == mLastSelectionContainer &&

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

@ -96,8 +96,6 @@ nsTransactionItem::GetIsBatch(bool *aIsBatch)
nsresult
nsTransactionItem::GetNumberOfChildren(int32_t *aNumChildren)
{
nsresult result;
NS_ENSURE_TRUE(aNumChildren, NS_ERROR_NULL_POINTER);
*aNumChildren = 0;
@ -105,13 +103,13 @@ nsTransactionItem::GetNumberOfChildren(int32_t *aNumChildren)
int32_t ui = 0;
int32_t ri = 0;
result = GetNumberOfUndoItems(&ui);
nsresult rv = GetNumberOfUndoItems(&ui);
NS_ENSURE_SUCCESS(result, result);
NS_ENSURE_SUCCESS(rv, rv);
result = GetNumberOfRedoItems(&ri);
rv = GetNumberOfRedoItems(&ri);
NS_ENSURE_SUCCESS(result, result);
NS_ENSURE_SUCCESS(rv, rv);
*aNumChildren = ui + ri;
@ -126,21 +124,22 @@ nsTransactionItem::GetChild(int32_t aIndex, nsTransactionItem **aChild)
*aChild = 0;
int32_t numItems = 0;
nsresult result = GetNumberOfChildren(&numItems);
nsresult rv = GetNumberOfChildren(&numItems);
NS_ENSURE_SUCCESS(result, result);
NS_ENSURE_SUCCESS(rv, rv);
if (aIndex < 0 || aIndex >= numItems)
if (aIndex < 0 || aIndex >= numItems) {
return NS_ERROR_FAILURE;
}
// Children are expected to be in the order they were added,
// so the child first added would be at the bottom of the undo
// stack, or if there are no items on the undo stack, it would
// be at the top of the redo stack.
result = GetNumberOfUndoItems(&numItems);
rv = GetNumberOfUndoItems(&numItems);
NS_ENSURE_SUCCESS(result, result);
NS_ENSURE_SUCCESS(rv, rv);
if (numItems > 0 && aIndex < numItems) {
NS_ENSURE_TRUE(mUndoStack, NS_ERROR_FAILURE);
@ -154,9 +153,9 @@ nsTransactionItem::GetChild(int32_t aIndex, nsTransactionItem **aChild)
aIndex -= numItems;
result = GetNumberOfRedoItems(&numItems);
rv = GetNumberOfRedoItems(&numItems);
NS_ENSURE_SUCCESS(result, result);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(mRedoStack && numItems != 0 && aIndex < numItems, NS_ERROR_FAILURE);
@ -168,29 +167,31 @@ nsTransactionItem::GetChild(int32_t aIndex, nsTransactionItem **aChild)
nsresult
nsTransactionItem::DoTransaction()
{
if (mTransaction)
if (mTransaction) {
return mTransaction->DoTransaction();
}
return NS_OK;
}
nsresult
nsTransactionItem::UndoTransaction(nsTransactionManager *aTxMgr)
{
nsresult result = UndoChildren(aTxMgr);
nsresult rv = UndoChildren(aTxMgr);
if (NS_FAILED(result)) {
if (NS_FAILED(rv)) {
RecoverFromUndoError(aTxMgr);
return result;
return rv;
}
if (!mTransaction)
if (!mTransaction) {
return NS_OK;
}
result = mTransaction->UndoTransaction();
rv = mTransaction->UndoTransaction();
if (NS_FAILED(result)) {
if (NS_FAILED(rv)) {
RecoverFromUndoError(aTxMgr);
return result;
return rv;
}
return NS_OK;
@ -200,7 +201,6 @@ nsresult
nsTransactionItem::UndoChildren(nsTransactionManager *aTxMgr)
{
RefPtr<nsTransactionItem> item;
nsresult result = NS_OK;
int32_t sz = 0;
if (mUndoStack) {
@ -211,6 +211,7 @@ nsTransactionItem::UndoChildren(nsTransactionManager *aTxMgr)
/* Undo all of the transaction items children! */
sz = mUndoStack->GetSize();
nsresult rv = NS_OK;
while (sz-- > 0) {
item = mUndoStack->Peek();
@ -222,51 +223,53 @@ nsTransactionItem::UndoChildren(nsTransactionManager *aTxMgr)
bool doInterrupt = false;
result = aTxMgr->WillUndoNotify(t, &doInterrupt);
rv = aTxMgr->WillUndoNotify(t, &doInterrupt);
if (NS_FAILED(result)) {
return result;
if (NS_FAILED(rv)) {
return rv;
}
if (doInterrupt) {
return NS_OK;
}
result = item->UndoTransaction(aTxMgr);
rv = item->UndoTransaction(aTxMgr);
if (NS_SUCCEEDED(result)) {
if (NS_SUCCEEDED(rv)) {
item = mUndoStack->Pop();
mRedoStack->Push(item.forget());
}
nsresult result2 = aTxMgr->DidUndoNotify(t, result);
nsresult rv2 = aTxMgr->DidUndoNotify(t, rv);
if (NS_SUCCEEDED(result)) {
result = result2;
if (NS_SUCCEEDED(rv)) {
rv = rv2;
}
}
// XXX NS_OK if there is no Undo items or all methods work fine, otherwise,
// the result of the last item's UndoTransaction() or
// DidUndoNotify() if UndoTransaction() succeeded.
return rv;
}
return result;
return NS_OK;
}
nsresult
nsTransactionItem::RedoTransaction(nsTransactionManager *aTxMgr)
{
nsresult result;
nsCOMPtr<nsITransaction> transaction(mTransaction);
if (transaction) {
result = transaction->RedoTransaction();
nsresult rv = transaction->RedoTransaction();
NS_ENSURE_SUCCESS(result, result);
NS_ENSURE_SUCCESS(rv, rv);
}
result = RedoChildren(aTxMgr);
nsresult rv = RedoChildren(aTxMgr);
if (NS_FAILED(result)) {
if (NS_FAILED(rv)) {
RecoverFromRedoError(aTxMgr);
return result;
return rv;
}
return NS_OK;
@ -276,14 +279,15 @@ nsresult
nsTransactionItem::RedoChildren(nsTransactionManager *aTxMgr)
{
RefPtr<nsTransactionItem> item;
nsresult result = NS_OK;
if (!mRedoStack)
if (!mRedoStack) {
return NS_OK;
}
/* Redo all of the transaction items children! */
int32_t sz = mRedoStack->GetSize();
nsresult rv = NS_OK;
while (sz-- > 0) {
item = mRedoStack->Peek();
@ -295,31 +299,34 @@ nsTransactionItem::RedoChildren(nsTransactionManager *aTxMgr)
bool doInterrupt = false;
result = aTxMgr->WillRedoNotify(t, &doInterrupt);
rv = aTxMgr->WillRedoNotify(t, &doInterrupt);
if (NS_FAILED(result)) {
return result;
if (NS_FAILED(rv)) {
return rv;
}
if (doInterrupt) {
return NS_OK;
}
result = item->RedoTransaction(aTxMgr);
rv = item->RedoTransaction(aTxMgr);
if (NS_SUCCEEDED(result)) {
if (NS_SUCCEEDED(rv)) {
item = mRedoStack->Pop();
mUndoStack->Push(item.forget());
}
nsresult result2 = aTxMgr->DidUndoNotify(t, result);
// XXX Shouldn't this DidRedoNotify()? (bug 1311626)
nsresult rv2 = aTxMgr->DidUndoNotify(t, rv);
if (NS_SUCCEEDED(result)) {
result = result2;
if (NS_SUCCEEDED(rv)) {
rv = rv2;
}
}
return result;
// XXX NS_OK if there is no Redo items or all methods work fine, otherwise,
// the result of the last item's RedoTransaction() or
// DidUndoNotify() if UndoTransaction() succeeded.
return rv;
}
nsresult
@ -371,16 +378,15 @@ nsTransactionItem::RecoverFromRedoError(nsTransactionManager *aTxMgr)
// then undo the transaction item itself.
//
nsresult result;
nsresult rv = UndoChildren(aTxMgr);
result = UndoChildren(aTxMgr);
if (NS_FAILED(result)) {
return result;
if (NS_FAILED(rv)) {
return rv;
}
if (!mTransaction)
if (!mTransaction) {
return NS_OK;
}
return mTransaction->UndoTransaction();
}

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

@ -49,14 +49,13 @@ NS_IMETHODIMP nsTransactionList::GetNumItems(int32_t *aNumItems)
NS_ENSURE_TRUE(txMgr, NS_ERROR_FAILURE);
nsresult result = NS_OK;
if (mTxnStack)
if (mTxnStack) {
*aNumItems = mTxnStack->GetSize();
else if (mTxnItem)
result = mTxnItem->GetNumberOfChildren(aNumItems);
} else if (mTxnItem) {
return mTxnItem->GetNumberOfChildren(aNumItems);
}
return result;
return NS_OK;
}
NS_IMETHODIMP nsTransactionList::ItemIsBatch(int32_t aIndex, bool *aIsBatch)
@ -71,14 +70,12 @@ NS_IMETHODIMP nsTransactionList::ItemIsBatch(int32_t aIndex, bool *aIsBatch)
RefPtr<nsTransactionItem> item;
nsresult result = NS_OK;
if (mTxnStack)
if (mTxnStack) {
item = mTxnStack->GetItem(aIndex);
else if (mTxnItem)
result = mTxnItem->GetChild(aIndex, getter_AddRefs(item));
NS_ENSURE_SUCCESS(result, result);
} else if (mTxnItem) {
nsresult rv = mTxnItem->GetChild(aIndex, getter_AddRefs(item));
NS_ENSURE_SUCCESS(rv, rv);
}
NS_ENSURE_TRUE(item, NS_ERROR_FAILURE);
@ -98,8 +95,8 @@ NS_IMETHODIMP nsTransactionList::GetData(int32_t aIndex,
if (mTxnStack) {
item = mTxnStack->GetItem(aIndex);
} else if (mTxnItem) {
nsresult result = mTxnItem->GetChild(aIndex, getter_AddRefs(item));
NS_ENSURE_SUCCESS(result, result);
nsresult rv = mTxnItem->GetChild(aIndex, getter_AddRefs(item));
NS_ENSURE_SUCCESS(rv, rv);
}
nsCOMArray<nsISupports>& data = item->GetData();
@ -129,14 +126,12 @@ NS_IMETHODIMP nsTransactionList::GetItem(int32_t aIndex, nsITransaction **aItem)
RefPtr<nsTransactionItem> item;
nsresult result = NS_OK;
if (mTxnStack)
if (mTxnStack) {
item = mTxnStack->GetItem(aIndex);
else if (mTxnItem)
result = mTxnItem->GetChild(aIndex, getter_AddRefs(item));
NS_ENSURE_SUCCESS(result, result);
} else if (mTxnItem) {
nsresult rv = mTxnItem->GetChild(aIndex, getter_AddRefs(item));
NS_ENSURE_SUCCESS(rv, rv);
}
NS_ENSURE_TRUE(item, NS_ERROR_FAILURE);
@ -157,14 +152,12 @@ NS_IMETHODIMP nsTransactionList::GetNumChildrenForItem(int32_t aIndex, int32_t *
RefPtr<nsTransactionItem> item;
nsresult result = NS_OK;
if (mTxnStack)
if (mTxnStack) {
item = mTxnStack->GetItem(aIndex);
else if (mTxnItem)
result = mTxnItem->GetChild(aIndex, getter_AddRefs(item));
NS_ENSURE_SUCCESS(result, result);
} else if (mTxnItem) {
nsresult rv = mTxnItem->GetChild(aIndex, getter_AddRefs(item));
NS_ENSURE_SUCCESS(rv, rv);
}
NS_ENSURE_TRUE(item, NS_ERROR_FAILURE);
@ -183,14 +176,12 @@ NS_IMETHODIMP nsTransactionList::GetChildListForItem(int32_t aIndex, nsITransact
RefPtr<nsTransactionItem> item;
nsresult result = NS_OK;
if (mTxnStack)
if (mTxnStack) {
item = mTxnStack->GetItem(aIndex);
else if (mTxnItem)
result = mTxnItem->GetChild(aIndex, getter_AddRefs(item));
NS_ENSURE_SUCCESS(result, result);
} else if (mTxnItem) {
nsresult rv = mTxnItem->GetChild(aIndex, getter_AddRefs(item));
NS_ENSURE_SUCCESS(rv, rv);
}
NS_ENSURE_TRUE(item, NS_ERROR_FAILURE);
@ -202,4 +193,3 @@ NS_IMETHODIMP nsTransactionList::GetChildListForItem(int32_t aIndex, nsITransact
return NS_OK;
}

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

@ -59,45 +59,43 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(nsTransactionManager)
NS_IMETHODIMP
nsTransactionManager::DoTransaction(nsITransaction *aTransaction)
{
nsresult result;
NS_ENSURE_TRUE(aTransaction, NS_ERROR_NULL_POINTER);
bool doInterrupt = false;
result = WillDoNotify(aTransaction, &doInterrupt);
nsresult rv = WillDoNotify(aTransaction, &doInterrupt);
if (NS_FAILED(result)) {
return result;
if (NS_FAILED(rv)) {
return rv;
}
if (doInterrupt) {
return NS_OK;
}
result = BeginTransaction(aTransaction, nullptr);
rv = BeginTransaction(aTransaction, nullptr);
if (NS_FAILED(result)) {
DidDoNotify(aTransaction, result);
return result;
if (NS_FAILED(rv)) {
DidDoNotify(aTransaction, rv);
return rv;
}
result = EndTransaction(false);
rv = EndTransaction(false);
nsresult result2 = DidDoNotify(aTransaction, result);
nsresult rv2 = DidDoNotify(aTransaction, rv);
if (NS_SUCCEEDED(result)) {
result = result2;
if (NS_SUCCEEDED(rv)) {
rv = rv2;
}
return result;
// XXX The result of EndTransaction() or DidDoNotify() if EndTransaction()
// succeeded.
return rv;
}
NS_IMETHODIMP
nsTransactionManager::UndoTransaction()
{
nsresult result = NS_OK;
// It is illegal to call UndoTransaction() while the transaction manager is
// executing a transaction's DoTransaction() method! If this happens,
// the UndoTransaction() request is ignored, and we return NS_ERROR_FAILURE.
@ -119,37 +117,37 @@ nsTransactionManager::UndoTransaction()
bool doInterrupt = false;
result = WillUndoNotify(t, &doInterrupt);
nsresult rv = WillUndoNotify(t, &doInterrupt);
if (NS_FAILED(result)) {
return result;
if (NS_FAILED(rv)) {
return rv;
}
if (doInterrupt) {
return NS_OK;
}
result = tx->UndoTransaction(this);
rv = tx->UndoTransaction(this);
if (NS_SUCCEEDED(result)) {
if (NS_SUCCEEDED(rv)) {
tx = mUndoStack.Pop();
mRedoStack.Push(tx.forget());
}
nsresult result2 = DidUndoNotify(t, result);
nsresult rv2 = DidUndoNotify(t, rv);
if (NS_SUCCEEDED(result)) {
result = result2;
if (NS_SUCCEEDED(rv)) {
rv = rv2;
}
return result;
// XXX The result of UndoTransaction() or DidUndoNotify() if UndoTransaction()
// succeeded.
return rv;
}
NS_IMETHODIMP
nsTransactionManager::RedoTransaction()
{
nsresult result = NS_OK;
// It is illegal to call RedoTransaction() while the transaction manager is
// executing a transaction's DoTransaction() method! If this happens,
// the RedoTransaction() request is ignored, and we return NS_ERROR_FAILURE.
@ -171,53 +169,49 @@ nsTransactionManager::RedoTransaction()
bool doInterrupt = false;
result = WillRedoNotify(t, &doInterrupt);
nsresult rv = WillRedoNotify(t, &doInterrupt);
if (NS_FAILED(result)) {
return result;
if (NS_FAILED(rv)) {
return rv;
}
if (doInterrupt) {
return NS_OK;
}
result = tx->RedoTransaction(this);
rv = tx->RedoTransaction(this);
if (NS_SUCCEEDED(result)) {
if (NS_SUCCEEDED(rv)) {
tx = mRedoStack.Pop();
mUndoStack.Push(tx.forget());
}
nsresult result2 = DidRedoNotify(t, result);
nsresult rv2 = DidRedoNotify(t, rv);
if (NS_SUCCEEDED(result)) {
result = result2;
if (NS_SUCCEEDED(rv)) {
rv = rv2;
}
return result;
// XXX The result of RedoTransaction() or DidRedoNotify() if RedoTransaction()
// succeeded.
return rv;
}
NS_IMETHODIMP
nsTransactionManager::Clear()
{
nsresult result;
nsresult rv = ClearRedoStack();
result = ClearRedoStack();
if (NS_FAILED(result)) {
return result;
if (NS_FAILED(rv)) {
return rv;
}
result = ClearUndoStack();
return result;
return ClearUndoStack();
}
NS_IMETHODIMP
nsTransactionManager::BeginBatch(nsISupports* aData)
{
nsresult result;
// We can batch independent transactions together by simply pushing
// a dummy transaction item on the do stack. This dummy transaction item
// will be popped off the do stack, and then pushed on the undo stack
@ -225,33 +219,32 @@ nsTransactionManager::BeginBatch(nsISupports* aData)
bool doInterrupt = false;
result = WillBeginBatchNotify(&doInterrupt);
nsresult rv = WillBeginBatchNotify(&doInterrupt);
if (NS_FAILED(result)) {
return result;
if (NS_FAILED(rv)) {
return rv;
}
if (doInterrupt) {
return NS_OK;
}
result = BeginTransaction(0, aData);
rv = BeginTransaction(0, aData);
nsresult result2 = DidBeginBatchNotify(result);
nsresult rv2 = DidBeginBatchNotify(rv);
if (NS_SUCCEEDED(result)) {
result = result2;
if (NS_SUCCEEDED(rv)) {
rv = rv2;
}
return result;
// XXX The result of BeginTransaction() or DidBeginBatchNotify() if
// BeginTransaction() succeeded.
return rv;
}
NS_IMETHODIMP
nsTransactionManager::EndBatch(bool aAllowEmpty)
{
nsCOMPtr<nsITransaction> ti;
nsresult result;
// XXX: Need to add some mechanism to detect the case where the transaction
// at the top of the do stack isn't the dummy transaction, so we can
// throw an error!! This can happen if someone calls EndBatch() within
@ -265,6 +258,7 @@ nsTransactionManager::EndBatch(bool aAllowEmpty)
RefPtr<nsTransactionItem> tx = mDoStack.Peek();
nsCOMPtr<nsITransaction> ti;
if (tx) {
ti = tx->GetTransaction();
}
@ -275,25 +269,27 @@ nsTransactionManager::EndBatch(bool aAllowEmpty)
bool doInterrupt = false;
result = WillEndBatchNotify(&doInterrupt);
nsresult rv = WillEndBatchNotify(&doInterrupt);
if (NS_FAILED(result)) {
return result;
if (NS_FAILED(rv)) {
return rv;
}
if (doInterrupt) {
return NS_OK;
}
result = EndTransaction(aAllowEmpty);
rv = EndTransaction(aAllowEmpty);
nsresult result2 = DidEndBatchNotify(result);
nsresult rv2 = DidEndBatchNotify(rv);
if (NS_SUCCEEDED(result)) {
result = result2;
if (NS_SUCCEEDED(rv)) {
rv = rv2;
}
return result;
// XXX The result of EndTransaction() or DidEndBatchNotify() if
// EndTransaction() succeeded.
return rv;
}
NS_IMETHODIMP
@ -470,7 +466,7 @@ nsTransactionManager::BatchTopUndo()
previousUndo = mUndoStack.Peek();
MOZ_ASSERT(previousUndo, "There should be at least two transactions.");
nsresult result = previousUndo->AddChild(lastUndo);
nsresult rv = previousUndo->AddChild(lastUndo);
// Transfer data from the transactions that is going to be
// merged to the transaction that it is being merged with.
@ -479,7 +475,7 @@ nsTransactionManager::BatchTopUndo()
NS_ENSURE_TRUE(previousData.AppendObjects(lastData), NS_ERROR_UNEXPECTED);
lastData.Clear();
return result;
return rv;
}
nsresult
@ -526,210 +522,199 @@ nsTransactionManager::ClearRedoStack()
nsresult
nsTransactionManager::WillDoNotify(nsITransaction *aTransaction, bool *aInterrupt)
{
nsresult result = NS_OK;
for (int32_t i = 0, lcount = mListeners.Count(); i < lcount; i++) {
nsITransactionListener *listener = mListeners[i];
nsITransactionListener* listener = mListeners[i];
NS_ENSURE_TRUE(listener, NS_ERROR_FAILURE);
result = listener->WillDo(this, aTransaction, aInterrupt);
nsresult rv = listener->WillDo(this, aTransaction, aInterrupt);
if (NS_FAILED(result) || *aInterrupt) {
break;
if (NS_FAILED(rv) || *aInterrupt) {
return rv;
}
}
return result;
return NS_OK;
}
nsresult
nsTransactionManager::DidDoNotify(nsITransaction *aTransaction, nsresult aDoResult)
{
nsresult result = NS_OK;
for (int32_t i = 0, lcount = mListeners.Count(); i < lcount; i++) {
nsITransactionListener *listener = mListeners[i];
nsITransactionListener* listener = mListeners[i];
NS_ENSURE_TRUE(listener, NS_ERROR_FAILURE);
result = listener->DidDo(this, aTransaction, aDoResult);
nsresult rv = listener->DidDo(this, aTransaction, aDoResult);
if (NS_FAILED(result)) {
break;
if (NS_FAILED(rv)) {
return rv;
}
}
return result;
return NS_OK;
}
nsresult
nsTransactionManager::WillUndoNotify(nsITransaction *aTransaction, bool *aInterrupt)
{
nsresult result = NS_OK;
for (int32_t i = 0, lcount = mListeners.Count(); i < lcount; i++) {
nsITransactionListener *listener = mListeners[i];
nsITransactionListener* listener = mListeners[i];
NS_ENSURE_TRUE(listener, NS_ERROR_FAILURE);
result = listener->WillUndo(this, aTransaction, aInterrupt);
nsresult rv = listener->WillUndo(this, aTransaction, aInterrupt);
if (NS_FAILED(result) || *aInterrupt) {
break;
if (NS_FAILED(rv) || *aInterrupt) {
return rv;
}
}
return result;
return NS_OK;
}
nsresult
nsTransactionManager::DidUndoNotify(nsITransaction *aTransaction, nsresult aUndoResult)
{
nsresult result = NS_OK;
for (int32_t i = 0, lcount = mListeners.Count(); i < lcount; i++) {
nsITransactionListener *listener = mListeners[i];
nsITransactionListener* listener = mListeners[i];
NS_ENSURE_TRUE(listener, NS_ERROR_FAILURE);
result = listener->DidUndo(this, aTransaction, aUndoResult);
nsresult rv = listener->DidUndo(this, aTransaction, aUndoResult);
if (NS_FAILED(result)) {
break;
if (NS_FAILED(rv)) {
return rv;
}
}
return result;
return NS_OK;
}
nsresult
nsTransactionManager::WillRedoNotify(nsITransaction *aTransaction, bool *aInterrupt)
{
nsresult result = NS_OK;
for (int32_t i = 0, lcount = mListeners.Count(); i < lcount; i++) {
nsITransactionListener *listener = mListeners[i];
nsITransactionListener* listener = mListeners[i];
NS_ENSURE_TRUE(listener, NS_ERROR_FAILURE);
result = listener->WillRedo(this, aTransaction, aInterrupt);
nsresult rv = listener->WillRedo(this, aTransaction, aInterrupt);
if (NS_FAILED(result) || *aInterrupt) {
break;
if (NS_FAILED(rv) || *aInterrupt) {
return rv;
}
}
return result;
return NS_OK;
}
nsresult
nsTransactionManager::DidRedoNotify(nsITransaction *aTransaction, nsresult aRedoResult)
{
nsresult result = NS_OK;
for (int32_t i = 0, lcount = mListeners.Count(); i < lcount; i++) {
nsITransactionListener *listener = mListeners[i];
nsITransactionListener* listener = mListeners[i];
NS_ENSURE_TRUE(listener, NS_ERROR_FAILURE);
result = listener->DidRedo(this, aTransaction, aRedoResult);
nsresult rv = listener->DidRedo(this, aTransaction, aRedoResult);
if (NS_FAILED(result)) {
break;
if (NS_FAILED(rv)) {
return rv;
}
}
return result;
return NS_OK;
}
nsresult
nsTransactionManager::WillBeginBatchNotify(bool *aInterrupt)
{
nsresult result = NS_OK;
for (int32_t i = 0, lcount = mListeners.Count(); i < lcount; i++) {
nsITransactionListener *listener = mListeners[i];
nsITransactionListener* listener = mListeners[i];
NS_ENSURE_TRUE(listener, NS_ERROR_FAILURE);
result = listener->WillBeginBatch(this, aInterrupt);
nsresult rv = listener->WillBeginBatch(this, aInterrupt);
if (NS_FAILED(result) || *aInterrupt) {
break;
if (NS_FAILED(rv) || *aInterrupt) {
return rv;
}
}
return result;
return NS_OK;
}
nsresult
nsTransactionManager::DidBeginBatchNotify(nsresult aResult)
{
nsresult result = NS_OK;
for (int32_t i = 0, lcount = mListeners.Count(); i < lcount; i++) {
nsITransactionListener *listener = mListeners[i];
nsITransactionListener* listener = mListeners[i];
NS_ENSURE_TRUE(listener, NS_ERROR_FAILURE);
result = listener->DidBeginBatch(this, aResult);
nsresult rv = listener->DidBeginBatch(this, aResult);
if (NS_FAILED(result)) {
break;
if (NS_FAILED(rv)) {
return rv;
}
}
return result;
return NS_OK;
}
nsresult
nsTransactionManager::WillEndBatchNotify(bool *aInterrupt)
{
nsresult result = NS_OK;
for (int32_t i = 0, lcount = mListeners.Count(); i < lcount; i++) {
nsITransactionListener *listener = mListeners[i];
nsITransactionListener* listener = mListeners[i];
NS_ENSURE_TRUE(listener, NS_ERROR_FAILURE);
result = listener->WillEndBatch(this, aInterrupt);
nsresult rv = listener->WillEndBatch(this, aInterrupt);
if (NS_FAILED(result) || *aInterrupt) {
break;
if (NS_FAILED(rv) || *aInterrupt) {
return rv;
}
}
return result;
return NS_OK;
}
nsresult
nsTransactionManager::DidEndBatchNotify(nsresult aResult)
{
nsresult result = NS_OK;
for (int32_t i = 0, lcount = mListeners.Count(); i < lcount; i++) {
nsITransactionListener *listener = mListeners[i];
nsITransactionListener* listener = mListeners[i];
NS_ENSURE_TRUE(listener, NS_ERROR_FAILURE);
result = listener->DidEndBatch(this, aResult);
nsresult rv = listener->DidEndBatch(this, aResult);
if (NS_FAILED(result)) {
break;
if (NS_FAILED(rv)) {
return rv;
}
}
return result;
return NS_OK;
}
nsresult
nsTransactionManager::WillMergeNotify(nsITransaction *aTop, nsITransaction *aTransaction, bool *aInterrupt)
{
nsresult result = NS_OK;
for (int32_t i = 0, lcount = mListeners.Count(); i < lcount; i++) {
nsITransactionListener *listener = mListeners[i];
nsITransactionListener* listener = mListeners[i];
NS_ENSURE_TRUE(listener, NS_ERROR_FAILURE);
result = listener->WillMerge(this, aTop, aTransaction, aInterrupt);
nsresult rv = listener->WillMerge(this, aTop, aTransaction, aInterrupt);
if (NS_FAILED(result) || *aInterrupt) {
break;
if (NS_FAILED(rv) || *aInterrupt) {
return rv;
}
}
return result;
return NS_OK;
}
nsresult
@ -738,28 +723,26 @@ nsTransactionManager::DidMergeNotify(nsITransaction *aTop,
bool aDidMerge,
nsresult aMergeResult)
{
nsresult result = NS_OK;
for (int32_t i = 0, lcount = mListeners.Count(); i < lcount; i++) {
nsITransactionListener *listener = mListeners[i];
nsITransactionListener* listener = mListeners[i];
NS_ENSURE_TRUE(listener, NS_ERROR_FAILURE);
result = listener->DidMerge(this, aTop, aTransaction, aDidMerge, aMergeResult);
nsresult rv =
listener->DidMerge(this, aTop, aTransaction, aDidMerge, aMergeResult);
if (NS_FAILED(result)) {
break;
if (NS_FAILED(rv)) {
return rv;
}
}
return result;
return NS_OK;
}
nsresult
nsTransactionManager::BeginTransaction(nsITransaction *aTransaction,
nsISupports *aData)
{
nsresult result = NS_OK;
// XXX: POSSIBLE OPTIMIZATION
// We could use a factory that pre-allocates/recycles transaction items.
RefPtr<nsTransactionItem> tx = new nsTransactionItem(aTransaction);
@ -775,11 +758,11 @@ nsTransactionManager::BeginTransaction(nsITransaction *aTransaction,
mDoStack.Push(tx);
result = tx->DoTransaction();
nsresult rv = tx->DoTransaction();
if (NS_FAILED(result)) {
if (NS_FAILED(rv)) {
tx = mDoStack.Pop();
return result;
return rv;
}
return NS_OK;
@ -788,8 +771,6 @@ nsTransactionManager::BeginTransaction(nsITransaction *aTransaction,
nsresult
nsTransactionManager::EndTransaction(bool aAllowEmpty)
{
nsresult result = NS_OK;
RefPtr<nsTransactionItem> tx = mDoStack.Pop();
if (!tx) {
@ -807,7 +788,7 @@ nsTransactionManager::EndTransaction(bool aAllowEmpty)
tx->GetNumberOfChildren(&nc);
if (!nc) {
return result;
return NS_OK;
}
}
@ -815,15 +796,15 @@ nsTransactionManager::EndTransaction(bool aAllowEmpty)
// more to do, just return.
bool isTransient = false;
nsresult rv = NS_OK;
if (tint) {
result = tint->GetIsTransient(&isTransient);
rv = tint->GetIsTransient(&isTransient);
}
if (NS_FAILED(result) || isTransient || !mMaxTransactionCount) {
if (NS_FAILED(rv) || isTransient || !mMaxTransactionCount) {
// XXX: Should we be clearing the redo stack if the transaction
// is transient and there is nothing on the do stack?
return result;
return rv;
}
// Check if there is a transaction on the do stack. If there is,
@ -832,18 +813,14 @@ nsTransactionManager::EndTransaction(bool aAllowEmpty)
RefPtr<nsTransactionItem> top = mDoStack.Peek();
if (top) {
result = top->AddChild(tx);
// XXX: What do we do if this fails?
return result;
return top->AddChild(tx); // XXX: What do we do if this fails?
}
// The transaction succeeded, so clear the redo stack.
result = ClearRedoStack();
rv = ClearRedoStack();
if (NS_FAILED(result)) {
if (NS_FAILED(rv)) {
// XXX: What do we do if this fails?
}
@ -860,25 +837,25 @@ nsTransactionManager::EndTransaction(bool aAllowEmpty)
bool doInterrupt = false;
result = WillMergeNotify(topTransaction, tint, &doInterrupt);
rv = WillMergeNotify(topTransaction, tint, &doInterrupt);
NS_ENSURE_SUCCESS(result, result);
NS_ENSURE_SUCCESS(rv, rv);
if (!doInterrupt) {
result = topTransaction->Merge(tint, &didMerge);
rv = topTransaction->Merge(tint, &didMerge);
nsresult result2 = DidMergeNotify(topTransaction, tint, didMerge, result);
nsresult rv2 = DidMergeNotify(topTransaction, tint, didMerge, rv);
if (NS_SUCCEEDED(result)) {
result = result2;
if (NS_SUCCEEDED(rv)) {
rv = rv2;
}
if (NS_FAILED(result)) {
if (NS_FAILED(rv)) {
// XXX: What do we do if this fails?
}
if (didMerge) {
return result;
return rv;
}
}
}
@ -899,4 +876,3 @@ nsTransactionManager::EndTransaction(bool aAllowEmpty)
return NS_OK;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -463,6 +463,11 @@ public:
, _41(a41), _42(a42), _43(a43), _44(a44)
{}
explicit Matrix4x4Typed(const Float aArray[16])
{
memcpy(components, aArray, sizeof(components));
}
Matrix4x4Typed(const Matrix4x4Typed& aOther)
{
memcpy(this, &aOther, sizeof(*this));

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

@ -5,7 +5,6 @@
#include "GLContextProvider.h"
#include "GLContextCGL.h"
#include "TextureImageCGL.h"
#include "nsDebug.h"
#include "nsIWidget.h"
#include <OpenGL/gl.h>

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

@ -15,9 +15,6 @@
#include "GfxTexturesReporter.h"
#include "TextureImageEGL.h"
#ifdef XP_MACOSX
#include "TextureImageCGL.h"
#endif
using namespace mozilla::gfx;
@ -33,10 +30,6 @@ CreateTextureImage(GLContext* gl,
TextureImage::ImageFormat aImageFormat)
{
switch (gl->GetContextType()) {
#ifdef XP_MACOSX
case GLContextType::CGL:
return CreateTextureImageCGL(gl, aSize, aContentType, aWrapMode, aFlags, aImageFormat);
#endif
case GLContextType::EGL:
return CreateTextureImageEGL(gl, aSize, aContentType, aWrapMode, aFlags, aImageFormat);
default: {
@ -61,10 +54,6 @@ TileGenFunc(GLContext* gl,
TextureImage::ImageFormat aImageFormat)
{
switch (gl->GetContextType()) {
#ifdef XP_MACOSX
case GLContextType::CGL:
return TileGenFuncCGL(gl, aSize, aContentType, aFlags);
#endif
case GLContextType::EGL:
return TileGenFuncEGL(gl, aSize, aContentType, aFlags, aImageFormat);
default:
@ -131,77 +120,6 @@ BasicTextureImage::~BasicTextureImage()
}
}
gfx::DrawTarget*
BasicTextureImage::BeginUpdate(nsIntRegion& aRegion)
{
NS_ASSERTION(!mUpdateDrawTarget, "BeginUpdate() without EndUpdate()?");
// determine the region the client will need to repaint
if (CanUploadSubTextures(mGLContext)) {
GetUpdateRegion(aRegion);
} else {
aRegion = IntRect(IntPoint(0, 0), mSize);
}
mUpdateRegion = aRegion;
IntRect rgnSize = mUpdateRegion.GetBounds();
if (!IntRect(IntPoint(0, 0), mSize).Contains(rgnSize)) {
NS_ERROR("update outside of image");
return nullptr;
}
gfx::SurfaceFormat format =
(GetContentType() == gfxContentType::COLOR) ?
gfx::SurfaceFormat::B8G8R8X8 : gfx::SurfaceFormat::B8G8R8A8;
mUpdateDrawTarget =
GetDrawTargetForUpdate(gfx::IntSize(rgnSize.width, rgnSize.height), format);
return mUpdateDrawTarget;
}
void
BasicTextureImage::GetUpdateRegion(nsIntRegion& aForRegion)
{
// if the texture hasn't been initialized yet, or something important
// changed, we need to recreate our backing surface and force the
// client to paint everything
if (mTextureState != Valid) {
aForRegion = IntRect(IntPoint(0, 0), mSize);
}
}
void
BasicTextureImage::EndUpdate()
{
NS_ASSERTION(!!mUpdateDrawTarget, "EndUpdate() without BeginUpdate()?");
// FIXME: this is the slow boat. Make me fast (with GLXPixmap?).
RefPtr<gfx::SourceSurface> updateSnapshot = mUpdateDrawTarget->Snapshot();
RefPtr<gfx::DataSourceSurface> updateData = updateSnapshot->GetDataSurface();
bool relative = FinishedSurfaceUpdate();
bool needInit = mTextureState == Created;
size_t uploadSize;
mTextureFormat =
UploadSurfaceToTexture(mGLContext,
updateData,
mUpdateRegion,
mTexture,
&uploadSize,
needInit,
mUpdateOffset,
relative);
FinishedSurfaceUpload();
if (uploadSize > 0) {
UpdateUploadSize(uploadSize);
}
mUpdateDrawTarget = nullptr;
mTextureState = Valid;
}
void
BasicTextureImage::BindTexture(GLenum aTextureUnit)
{
@ -210,46 +128,28 @@ BasicTextureImage::BindTexture(GLenum aTextureUnit)
mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
}
already_AddRefed<gfx::DrawTarget>
BasicTextureImage::GetDrawTargetForUpdate(const gfx::IntSize& aSize, gfx::SurfaceFormat aFmt)
{
return gfx::Factory::CreateDrawTarget(gfx::BackendType::CAIRO, aSize, aFmt);
}
bool
BasicTextureImage::FinishedSurfaceUpdate()
{
return false;
}
void
BasicTextureImage::FinishedSurfaceUpload()
{
}
bool
BasicTextureImage::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom /* = gfx::IntPoint(0, 0) */)
{
IntRect bounds = aRegion.GetBounds();
nsIntRegion region;
if (mTextureState != Valid) {
bounds = IntRect(0, 0, mSize.width, mSize.height);
region = nsIntRegion(bounds);
} else {
if (mTextureState == Valid) {
region = aRegion;
} else {
region = nsIntRegion(IntRect(0, 0, mSize.width, mSize.height));
}
size_t uploadSize;
bool needInit = mTextureState == Created;
size_t uploadSize;
mTextureFormat =
UploadSurfaceToTexture(mGLContext,
aSurf,
region,
mTexture,
mSize,
&uploadSize,
needInit,
bounds.TopLeft() + IntPoint(aFrom.x, aFrom.y),
false);
aFrom);
if (uploadSize > 0) {
UpdateUploadSize(uploadSize);
}
@ -260,8 +160,6 @@ BasicTextureImage::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion
void
BasicTextureImage::Resize(const gfx::IntSize& aSize)
{
NS_ASSERTION(!mUpdateDrawTarget, "Resize() while in update?");
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
// This matches the logic in UploadImageDataToTexture so that
@ -317,7 +215,6 @@ BasicTextureImage::BasicTextureImage(GLuint aTexture,
, mTexture(aTexture)
, mTextureState(Created)
, mGLContext(aContext)
, mUpdateOffset(0, 0)
{}
static bool
@ -347,7 +244,6 @@ TiledTextureImage::TiledTextureImage(GLContext* aGL,
, mCurrentImage(0)
, mIterationCallback(nullptr)
, mIterationCallbackData(nullptr)
, mInUpdate(false)
, mRows(0)
, mColumns(0)
, mGL(aGL)
@ -398,13 +294,7 @@ TiledTextureImage::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion
if (tileRegion.IsEmpty())
continue;
if (CanUploadSubTextures(mGL)) {
tileRegion.MoveBy(-xPos, -yPos); // translate into tile local space
} else {
// If sub-textures are unsupported, expand to tile boundaries
tileRect.x = tileRect.y = 0;
tileRegion = nsIntRegion(tileRect);
}
tileRegion.MoveBy(-xPos, -yPos); // translate into tile local space
result &= mImages[mCurrentImage]->
DirectUpdate(aSurf, tileRegion, aFrom + gfx::IntPoint(xPos, yPos));
@ -426,153 +316,6 @@ TiledTextureImage::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion
return result;
}
void
TiledTextureImage::GetUpdateRegion(nsIntRegion& aForRegion)
{
if (mTextureState != Valid) {
// if the texture hasn't been initialized yet, or something important
// changed, we need to recreate our backing surface and force the
// client to paint everything
aForRegion = IntRect(IntPoint(0, 0), mSize);
return;
}
nsIntRegion newRegion;
// We need to query each texture with the region it will be drawing and
// set aForRegion to be the combination of all of these regions
for (unsigned i = 0; i < mImages.Length(); i++) {
int xPos = (i % mColumns) * mTileSize;
int yPos = (i / mColumns) * mTileSize;
IntRect imageRect = IntRect(IntPoint(xPos,yPos),
mImages[i]->GetSize());
if (aForRegion.Intersects(imageRect)) {
// Make a copy of the region
nsIntRegion subRegion;
subRegion.And(aForRegion, imageRect);
// Translate it into tile-space
subRegion.MoveBy(-xPos, -yPos);
// Query region
mImages[i]->GetUpdateRegion(subRegion);
// Translate back
subRegion.MoveBy(xPos, yPos);
// Add to the accumulated region
newRegion.Or(newRegion, subRegion);
}
}
aForRegion = newRegion;
}
gfx::DrawTarget*
TiledTextureImage::BeginUpdate(nsIntRegion& aRegion)
{
NS_ASSERTION(!mInUpdate, "nested update");
mInUpdate = true;
// Note, we don't call GetUpdateRegion here as if the updated region is
// fully contained in a single tile, we get to avoid iterating through
// the tiles again (and a little copying).
if (mTextureState != Valid)
{
// if the texture hasn't been initialized yet, or something important
// changed, we need to recreate our backing surface and force the
// client to paint everything
aRegion = IntRect(IntPoint(0, 0), mSize);
}
IntRect bounds = aRegion.GetBounds();
for (unsigned i = 0; i < mImages.Length(); i++) {
int xPos = (i % mColumns) * mTileSize;
int yPos = (i / mColumns) * mTileSize;
nsIntRegion imageRegion =
nsIntRegion(IntRect(IntPoint(xPos,yPos),
mImages[i]->GetSize()));
// a single Image can handle this update request
if (imageRegion.Contains(aRegion)) {
// adjust for tile offset
aRegion.MoveBy(-xPos, -yPos);
// forward the actual call
RefPtr<gfx::DrawTarget> drawTarget = mImages[i]->BeginUpdate(aRegion);
// caller expects container space
aRegion.MoveBy(xPos, yPos);
// we don't have a temp surface
mUpdateDrawTarget = nullptr;
// remember which image to EndUpdate
mCurrentImage = i;
return drawTarget.get();
}
}
// Get the real updated region, taking into account the capabilities of
// each TextureImage tile
GetUpdateRegion(aRegion);
mUpdateRegion = aRegion;
bounds = aRegion.GetBounds();
// update covers multiple Images - create a temp surface to paint in
gfx::SurfaceFormat format =
(GetContentType() == gfxContentType::COLOR) ?
gfx::SurfaceFormat::B8G8R8X8: gfx::SurfaceFormat::B8G8R8A8;
mUpdateDrawTarget = gfx::Factory::CreateDrawTarget(gfx::BackendType::CAIRO,
bounds.Size(),
format);
return mUpdateDrawTarget;;
}
void
TiledTextureImage::EndUpdate()
{
NS_ASSERTION(mInUpdate, "EndUpdate not in update");
if (!mUpdateDrawTarget) { // update was to a single TextureImage
mImages[mCurrentImage]->EndUpdate();
mInUpdate = false;
mTextureState = Valid;
mTextureFormat = mImages[mCurrentImage]->GetTextureFormat();
return;
}
RefPtr<gfx::SourceSurface> updateSnapshot = mUpdateDrawTarget->Snapshot();
RefPtr<gfx::DataSourceSurface> updateData = updateSnapshot->GetDataSurface();
// upload tiles from temp surface
for (unsigned i = 0; i < mImages.Length(); i++) {
int xPos = (i % mColumns) * mTileSize;
int yPos = (i / mColumns) * mTileSize;
IntRect imageRect = IntRect(IntPoint(xPos,yPos), mImages[i]->GetSize());
nsIntRegion subregion;
subregion.And(mUpdateRegion, imageRect);
if (subregion.IsEmpty())
continue;
subregion.MoveBy(-xPos, -yPos); // Tile-local space
// copy tile from temp target
gfx::DrawTarget* drawTarget = mImages[i]->BeginUpdate(subregion);
MOZ_ASSERT(drawTarget->GetBackendType() == BackendType::CAIRO,
"updateSnapshot should not have been converted to data");
gfxUtils::ClipToRegion(drawTarget, subregion);
Size size(updateData->GetSize().width,
updateData->GetSize().height);
drawTarget->DrawSurface(updateData,
Rect(Point(-xPos, -yPos), size),
Rect(Point(0, 0), size),
DrawSurfaceOptions(),
DrawOptions(1.0, CompositionOp::OP_SOURCE,
AntialiasMode::NONE));
drawTarget->PopClip();
mImages[i]->EndUpdate();
}
mUpdateDrawTarget = nullptr;
mInUpdate = false;
mTextureFormat = mImages[0]->GetTextureFormat();
mTextureState = Valid;
}
void TiledTextureImage::BeginBigImageIteration()
{
mCurrentImage = 0;

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

@ -27,20 +27,9 @@ namespace gl {
class GLContext;
/**
* A TextureImage encapsulates a surface that can be drawn to by a
* Thebes gfxContext and (hopefully efficiently!) synchronized to a
* texture in the server. TextureImages are associated with one and
* only one GLContext.
*
* Implementation note: TextureImages attempt to unify two categories
* of backends
*
* (1) proxy to server-side object that can be bound to a texture;
* e.g. Pixmap on X11.
*
* (2) efficient manager of texture memory; e.g. by having clients draw
* into a scratch buffer which is then uploaded with
* glTexSubImage2D().
* A TextureImage provides a mechanism to synchronize data from a
* surface to a texture in the server. TextureImages are associated
* with one and only one GLContext.
*/
class TextureImage
{
@ -70,46 +59,6 @@ public:
GLenum aWrapMode,
TextureImage::Flags aFlags = TextureImage::NoFlags);
/**
* Returns a gfxASurface for updating |aRegion| of the client's
* image if successul, nullptr if not. |aRegion|'s bounds must fit
* within Size(); its coordinate space (if any) is ignored. If
* the update begins successfully, the returned gfxASurface is
* owned by this. Otherwise, nullptr is returned.
*
* |aRegion| is an inout param: the returned region is what the
* client must repaint. Category (1) regions above can
* efficiently handle repaints to "scattered" regions, while (2)
* can only efficiently handle repaints to rects.
*
* Painting the returned surface outside of |aRegion| results
* in undefined behavior.
*
* BeginUpdate() calls cannot be "nested", and each successful
* BeginUpdate() must be followed by exactly one EndUpdate() (see
* below). Failure to do so can leave this in a possibly
* inconsistent state. Unsuccessful BeginUpdate()s must not be
* followed by EndUpdate().
*/
virtual gfx::DrawTarget* BeginUpdate(nsIntRegion& aRegion) = 0;
/**
* Retrieves the region that will require updating, given a
* region that needs to be updated. This can be used for
* making decisions about updating before calling BeginUpdate().
*
* |aRegion| is an inout param.
*/
virtual void GetUpdateRegion(nsIntRegion& aForRegion) {
}
/**
* Finish the active update and synchronize with the server, if
* necessary.
*
* BeginUpdate() must have been called exactly once before
* EndUpdate().
*/
virtual void EndUpdate() = 0;
/**
* The Image may contain several textures for different regions (tiles).
* These functions iterate over each sub texture image tile.
@ -143,18 +92,10 @@ public:
/**
* Set this TextureImage's size, and ensure a texture has been
* allocated. Must not be called between BeginUpdate and EndUpdate.
* allocated.
* After a resize, the contents are undefined.
*
* If this isn't implemented by a subclass, it will just perform
* a dummy BeginUpdate/EndUpdate pair.
*/
virtual void Resize(const gfx::IntSize& aSize) {
mSize = aSize;
nsIntRegion r(gfx::IntRect(0, 0, aSize.width, aSize.height));
BeginUpdate(r);
EndUpdate();
}
virtual void Resize(const gfx::IntSize& aSize) = 0;
/**
* Mark this texture as having valid contents. Call this after modifying
@ -175,8 +116,8 @@ public:
virtual void BindTexture(GLenum aTextureUnit) = 0;
/**
* Returns the image format of the texture. Only valid after a matching
* BeginUpdate/EndUpdate pair have been called.
* Returns the image format of the texture. Only valid after
* DirectUpdate has been called.
*/
virtual gfx::SurfaceFormat GetTextureFormat() {
return mTextureFormat;
@ -194,7 +135,6 @@ public:
gfx::IntSize GetSize() const;
ContentType GetContentType() const { return mContentType; }
virtual bool InUpdate() const = 0;
GLenum GetWrapMode() const { return mWrapMode; }
void SetSamplingFilter(gfx::SamplingFilter aSamplingFilter) {
@ -256,37 +196,17 @@ public:
virtual void BindTexture(GLenum aTextureUnit);
virtual gfx::DrawTarget* BeginUpdate(nsIntRegion& aRegion);
virtual void GetUpdateRegion(nsIntRegion& aForRegion);
virtual void EndUpdate();
virtual bool DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom = gfx::IntPoint(0,0));
virtual GLuint GetTextureID() { return mTexture; }
virtual already_AddRefed<gfx::DrawTarget>
GetDrawTargetForUpdate(const gfx::IntSize& aSize, gfx::SurfaceFormat aFmt);
virtual void MarkValid() { mTextureState = Valid; }
// Call when drawing into the update surface is complete.
// Returns true if textures should be upload with a relative
// offset - See UploadSurfaceToTexture.
virtual bool FinishedSurfaceUpdate();
// Call after surface data has been uploaded to a texture.
virtual void FinishedSurfaceUpload();
virtual bool InUpdate() const { return !!mUpdateDrawTarget; }
virtual void Resize(const gfx::IntSize& aSize);
protected:
GLuint mTexture;
TextureState mTextureState;
RefPtr<GLContext> mGLContext;
RefPtr<gfx::DrawTarget> mUpdateDrawTarget;
nsIntRegion mUpdateRegion;
// The offset into the update surface at which the update rect is located.
nsIntPoint mUpdateOffset;
};
/**
@ -305,9 +225,6 @@ public:
TextureImage::ImageFormat aImageFormat = gfx::SurfaceFormat::UNKNOWN);
~TiledTextureImage();
void DumpDiv();
virtual gfx::DrawTarget* BeginUpdate(nsIntRegion& aRegion);
virtual void GetUpdateRegion(nsIntRegion& aForRegion);
virtual void EndUpdate();
virtual void Resize(const gfx::IntSize& aSize);
virtual uint32_t GetTileCount();
virtual void BeginBigImageIteration();
@ -319,7 +236,6 @@ public:
return mImages[mCurrentImage]->GetTextureID();
}
virtual bool DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom = gfx::IntPoint(0,0));
virtual bool InUpdate() const { return mInUpdate; }
virtual void BindTexture(GLenum);
protected:
@ -329,14 +245,9 @@ protected:
BigImageIterationCallback mIterationCallback;
void* mIterationCallbackData;
nsTArray< RefPtr<TextureImage> > mImages;
bool mInUpdate;
unsigned int mTileSize;
unsigned int mRows, mColumns;
GLContext* mGL;
// A temporary draw target to faciliate cross-tile updates.
RefPtr<gfx::DrawTarget> mUpdateDrawTarget;
// The region of update requested
nsIntRegion mUpdateRegion;
TextureState mTextureState;
TextureImage::ImageFormat mImageFormat;
};

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

@ -356,43 +356,16 @@ UploadImageDataToTexture(GLContext* gl,
int32_t aStride,
SurfaceFormat aFormat,
const nsIntRegion& aDstRegion,
GLuint& aTexture,
GLuint aTexture,
const gfx::IntSize& aSize,
size_t* aOutUploadSize,
bool aNeedInit,
bool aPixelBuffer,
GLenum aTextureUnit,
GLenum aTextureTarget)
{
bool textureInited = aNeedInit ? false : true;
gl->MakeCurrent();
gl->fActiveTexture(aTextureUnit);
if (!aTexture) {
gl->fGenTextures(1, &aTexture);
gl->fBindTexture(aTextureTarget, aTexture);
gl->fTexParameteri(aTextureTarget,
LOCAL_GL_TEXTURE_MIN_FILTER,
LOCAL_GL_LINEAR);
gl->fTexParameteri(aTextureTarget,
LOCAL_GL_TEXTURE_MAG_FILTER,
LOCAL_GL_LINEAR);
gl->fTexParameteri(aTextureTarget,
LOCAL_GL_TEXTURE_WRAP_S,
LOCAL_GL_CLAMP_TO_EDGE);
gl->fTexParameteri(aTextureTarget,
LOCAL_GL_TEXTURE_WRAP_T,
LOCAL_GL_CLAMP_TO_EDGE);
textureInited = false;
} else {
gl->fBindTexture(aTextureTarget, aTexture);
}
nsIntRegion paintRegion;
if (!textureInited) {
paintRegion = nsIntRegion(aDstRegion.GetBounds());
} else {
paintRegion = aDstRegion;
}
gl->fBindTexture(aTextureTarget, aTexture);
GLenum format = 0;
GLenum internalFormat = 0;
@ -473,26 +446,39 @@ UploadImageDataToTexture(GLContext* gl,
NS_ASSERTION(false, "Unhandled image surface format!");
}
// Top left point of the region's bounding rectangle.
IntPoint topLeft = paintRegion.GetBounds().TopLeft();
if (aOutUploadSize) {
*aOutUploadSize = 0;
}
for (auto iter = paintRegion.RectIter(); !iter.Done(); iter.Next()) {
const IntRect& rect = iter.Get();
// The inital data pointer is at the top left point of the region's
// bounding rectangle. We need to find the offset of this rect
// within the region and adjust the data pointer accordingly.
unsigned char* rectData =
aData + DataOffset(rect.TopLeft() - topLeft, aStride, aFormat);
if (aNeedInit || !CanUploadSubTextures(gl)) {
// If the texture needs initialized, or we are unable to
// upload sub textures, then initialize and upload the entire
// texture.
TexImage2DHelper(gl,
aTextureTarget,
0,
internalFormat,
aSize.width,
aSize.height,
aStride,
pixelSize,
0,
format,
type,
aData);
NS_ASSERTION(textureInited || (rect.x == 0 && rect.y == 0),
"Must be uploading to the origin when we don't have an existing texture");
if (aOutUploadSize && aNeedInit) {
uint32_t texelSize = GetBytesPerTexel(internalFormat, type);
size_t numTexels = size_t(aSize.width) * size_t(aSize.height);
*aOutUploadSize += texelSize * numTexels;
}
} else {
// Upload each rect in the region to the texture
for (auto iter = aDstRegion.RectIter(); !iter.Done(); iter.Next()) {
const IntRect& rect = iter.Get();
const unsigned char* rectData =
aData + DataOffset(rect.TopLeft(), aStride, aFormat);
if (textureInited && CanUploadSubTextures(gl)) {
TexSubImage2DHelper(gl,
aTextureTarget,
0,
@ -505,25 +491,6 @@ UploadImageDataToTexture(GLContext* gl,
format,
type,
rectData);
} else {
TexImage2DHelper(gl,
aTextureTarget,
0,
internalFormat,
rect.width,
rect.height,
aStride,
pixelSize,
0,
format,
type,
rectData);
}
if (aOutUploadSize && !textureInited) {
uint32_t texelSize = GetBytesPerTexel(internalFormat, type);
size_t numTexels = size_t(rect.width) * size_t(rect.height);
*aOutUploadSize += texelSize * numTexels;
}
}
@ -534,22 +501,24 @@ SurfaceFormat
UploadSurfaceToTexture(GLContext* gl,
DataSourceSurface* aSurface,
const nsIntRegion& aDstRegion,
GLuint& aTexture,
GLuint aTexture,
const gfx::IntSize& aSize,
size_t* aOutUploadSize,
bool aNeedInit,
const gfx::IntPoint& aSrcPoint,
bool aPixelBuffer,
GLenum aTextureUnit,
GLenum aTextureTarget)
{
unsigned char* data = aPixelBuffer ? nullptr : aSurface->GetData();
int32_t stride = aSurface->Stride();
SurfaceFormat format = aSurface->GetFormat();
data += DataOffset(aSrcPoint, stride, format);
unsigned char* data = aSurface->GetData() +
DataOffset(aSrcPoint, stride, format);
return UploadImageDataToTexture(gl, data, stride, format,
aDstRegion, aTexture, aOutUploadSize,
aNeedInit, aPixelBuffer, aTextureUnit,
aTextureTarget);
aDstRegion, aTexture, aSize,
aOutUploadSize, aNeedInit,
aTextureUnit, aTextureTarget);
}
bool

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

@ -22,62 +22,56 @@ namespace gl {
class GLContext;
/**
* Creates a RGB/RGBA texture (or uses one provided) and uploads the surface
* contents to it within aSrcRect.
*
* aSrcRect.x/y will be uploaded to 0/0 in the texture, and the size
* of the texture with be aSrcRect.width/height.
*
* If an existing texture is passed through aTexture, it is assumed it
* has already been initialised with glTexImage2D (or this function),
* and that its size is equal to or greater than aSrcRect + aDstPoint.
* You can alternatively set the overwrite flag to true and have a new
* texture memory block allocated.
*
* The aDstPoint parameter is ignored if no texture was provided
* or aOverwrite is true.
*
* \param aData Image data to upload.
* \param aDstRegion Region of texture to upload to.
* \param aTexture Texture to use, or 0 to have one created for you.
* \param aOutUploadSize if set, the number of bytes the texture requires will be returned here
* \param aOverwrite Over an existing texture with a new one.
* \param aSrcPoint Offset into aSrc where the region's bound's
* TopLeft() sits.
* \param aPixelBuffer Pass true to upload texture data with an
* offset from the base data (generally for pixel buffer objects),
* otherwise textures are upload with an absolute pointer to the data.
* \param aTextureUnit, the texture unit used temporarily to upload the
* surface. This testure may be overridden, clients should not rely on
* the contents of this texture after this call or even on this
* texture unit being active.
* \return Surface format of this texture.
*/
* Uploads image data to an OpenGL texture, initializing the texture
* first if necessary.
*
* \param gl The GL Context to use.
* \param aData Start of image data of surface to upload.
* Corresponds to the first pixel of the texture.
* \param aStride The image data's stride.
* \param aFormat The image data's format.
* \param aDstRegion Region of the texture to upload.
* \param aTexture The OpenGL texture to use. Must refer to a valid texture.
* \param aSize The full size of the texture.
* \param aOutUploadSize If set, the number of bytes the texture requires will
* be returned here.
* \param aNeedInit Indicates whether a new texture must be allocated.
* \param aTextureUnit The texture unit used temporarily to upload the surface.
* This may be overridden, so clients should not rely on
* the aTexture being bound to aTextureUnit after this call,
* or even on aTextureUnit being active.
* \param aTextureTarget The texture target to use.
* \return Surface format of this texture.
*/
gfx::SurfaceFormat
UploadImageDataToTexture(GLContext* gl,
unsigned char* aData,
int32_t aStride,
gfx::SurfaceFormat aFormat,
const nsIntRegion& aDstRegion,
GLuint& aTexture,
GLuint aTexture,
const gfx::IntSize& aSize,
size_t* aOutUploadSize = nullptr,
bool aNeedInit = false,
bool aPixelBuffer = false,
GLenum aTextureUnit = LOCAL_GL_TEXTURE0,
GLenum aTextureTarget = LOCAL_GL_TEXTURE_2D);
/**
* Convenience wrapper around UploadImageDataToTexture for gfx::DataSourceSurface's.
*/
* Convenience wrapper around UploadImageDataToTexture for
* gfx::DataSourceSurface's.
*
* \param aSurface The surface from which to upload image data.
* \param aSrcPoint Offset into aSurface where this texture's data begins.
*/
gfx::SurfaceFormat
UploadSurfaceToTexture(GLContext* gl,
gfx::DataSourceSurface* aSurface,
const nsIntRegion& aDstRegion,
GLuint& aTexture,
GLuint aTexture,
const gfx::IntSize& aSize,
size_t* aOutUploadSize = nullptr,
bool aNeedInit = false,
const gfx::IntPoint& aSrcPoint = gfx::IntPoint(0, 0),
bool aPixelBuffer = false,
GLenum aTextureUnit = LOCAL_GL_TEXTURE0,
GLenum aTextureTarget = LOCAL_GL_TEXTURE_2D);

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

@ -1,57 +0,0 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef TextureImageCGL_h_
#define TextureImageCGL_h_
#include "GLTextureImage.h"
#include "GLContextTypes.h"
#include "nsSize.h"
namespace mozilla {
namespace gl {
class TextureImageCGL : public BasicTextureImage
{
public:
TextureImageCGL(GLuint aTexture,
const gfx::IntSize& aSize,
GLenum aWrapMode,
ContentType aContentType,
GLContext* aContext,
TextureImage::Flags aFlags = TextureImage::NoFlags);
~TextureImageCGL();
protected:
bool FinishedSurfaceUpdate();
void FinishedSurfaceUpload();
private:
GLuint mPixelBuffer;
bool mBoundPixelBuffer;
};
already_AddRefed<TextureImage>
CreateTextureImageCGL(GLContext* gl,
const gfx::IntSize& aSize,
TextureImage::ContentType aContentType,
GLenum aWrapMode,
TextureImage::Flags aFlags,
TextureImage::ImageFormat aImageFormat);
already_AddRefed<TextureImage>
TileGenFuncCGL(GLContext* gl,
const gfx::IntSize& aSize,
TextureImage::ContentType aContentType,
TextureImage::Flags aFlags);
} // namespace gl
} // namespace mozilla
#endif

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

@ -1,109 +0,0 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "TextureImageCGL.h"
#include "GLContext.h"
#include "gfx2DGlue.h"
#include "gfxQuartzSurface.h"
#include "gfxPlatform.h"
#include "gfxFailure.h"
namespace mozilla {
using namespace gfx;
namespace gl {
TextureImageCGL::TextureImageCGL(GLuint aTexture,
const IntSize& aSize,
GLenum aWrapMode,
ContentType aContentType,
GLContext* aContext,
TextureImage::Flags aFlags)
: BasicTextureImage(aTexture, aSize, aWrapMode, aContentType,
aContext, aFlags)
, mPixelBuffer(0)
, mBoundPixelBuffer(false)
{}
TextureImageCGL::~TextureImageCGL()
{
if (mPixelBuffer) {
mGLContext->MakeCurrent();
mGLContext->fDeleteBuffers(1, &mPixelBuffer);
}
}
bool
TextureImageCGL::FinishedSurfaceUpdate()
{
if (mBoundPixelBuffer) {
mGLContext->MakeCurrent();
mGLContext->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, mPixelBuffer);
mGLContext->fUnmapBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER);
return true;
}
return false;
}
void
TextureImageCGL::FinishedSurfaceUpload()
{
if (mBoundPixelBuffer) {
mGLContext->MakeCurrent();
mGLContext->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
mBoundPixelBuffer = false;
}
}
already_AddRefed<TextureImage>
CreateTextureImageCGL(GLContext* gl,
const gfx::IntSize& aSize,
TextureImage::ContentType aContentType,
GLenum aWrapMode,
TextureImage::Flags aFlags,
TextureImage::ImageFormat aImageFormat)
{
if (!gl->IsOffscreenSizeAllowed(aSize) &&
gfxPlatform::OffMainThreadCompositingEnabled()) {
NS_ASSERTION(aWrapMode == LOCAL_GL_CLAMP_TO_EDGE, "Can't support wrapping with tiles!");
RefPtr<TextureImage> t = new gl::TiledTextureImage(gl, aSize, aContentType,
aFlags, aImageFormat);
return t.forget();
}
return CreateBasicTextureImage(gl, aSize, aContentType, aWrapMode,
aFlags);
}
already_AddRefed<TextureImage>
TileGenFuncCGL(GLContext* gl,
const IntSize& aSize,
TextureImage::ContentType aContentType,
TextureImage::Flags aFlags)
{
bool useNearestFilter = aFlags & TextureImage::UseNearestFilter;
gl->MakeCurrent();
GLuint texture;
gl->fGenTextures(1, &texture);
gl->fActiveTexture(LOCAL_GL_TEXTURE0);
gl->fBindTexture(LOCAL_GL_TEXTURE_2D, texture);
GLint texfilter = useNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR;
gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter);
gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter);
gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
RefPtr<TextureImageCGL> teximage
(new TextureImageCGL(texture, aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType,
gl, aFlags));
return teximage.forget();
}
} // namespace gl
} // namespace mozilla

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

@ -95,105 +95,6 @@ TextureImageEGL::~TextureImageEGL()
DestroyEGLSurface();
}
void
TextureImageEGL::GetUpdateRegion(nsIntRegion& aForRegion)
{
if (mTextureState != Valid) {
// if the texture hasn't been initialized yet, force the
// client to paint everything
aForRegion = gfx::IntRect(gfx::IntPoint(0, 0), mSize);
}
// We can only draw a rectangle, not subregions due to
// the way that our texture upload functions work. If
// needed, we /could/ do multiple texture uploads if we have
// non-overlapping rects, but that's a tradeoff.
aForRegion = nsIntRegion(aForRegion.GetBounds());
}
gfx::DrawTarget*
TextureImageEGL::BeginUpdate(nsIntRegion& aRegion)
{
NS_ASSERTION(!mUpdateDrawTarget, "BeginUpdate() without EndUpdate()?");
// determine the region the client will need to repaint
GetUpdateRegion(aRegion);
mUpdateRect = aRegion.GetBounds();
//printf_stderr("BeginUpdate with updateRect [%d %d %d %d]\n", mUpdateRect.x, mUpdateRect.y, mUpdateRect.width, mUpdateRect.height);
if (!gfx::IntRect(gfx::IntPoint(0, 0), mSize).Contains(mUpdateRect)) {
NS_ERROR("update outside of image");
return nullptr;
}
//printf_stderr("creating image surface %dx%d format %d\n", mUpdateRect.width, mUpdateRect.height, mUpdateFormat);
mUpdateDrawTarget = gfx::Factory::CreateDrawTarget(gfx::BackendType::CAIRO,
gfx::IntSize(mUpdateRect.width, mUpdateRect.height),
mUpdateFormat);
return mUpdateDrawTarget;
}
void
TextureImageEGL::EndUpdate()
{
NS_ASSERTION(!!mUpdateDrawTarget, "EndUpdate() without BeginUpdate()?");
//printf_stderr("EndUpdate: slow path");
// This is the slower path -- we didn't have any way to set up
// a fast mapping between our cairo target surface and the GL
// texture, so we have to upload data.
RefPtr<gfx::SourceSurface> updateSurface = nullptr;
RefPtr<gfx::DataSourceSurface> uploadImage = nullptr;
gfx::IntSize updateSize(mUpdateRect.width, mUpdateRect.height);
NS_ASSERTION(mUpdateDrawTarget->GetSize() == updateSize,
"Upload image is the wrong size!");
updateSurface = mUpdateDrawTarget->Snapshot();
uploadImage = updateSurface->GetDataSurface();
if (!uploadImage) {
return;
}
mGLContext->MakeCurrent();
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
if (mTextureState != Valid) {
NS_ASSERTION(mUpdateRect.x == 0 && mUpdateRect.y == 0 &&
mUpdateRect.Size() == mSize,
"Bad initial update on non-created texture!");
mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D,
0,
GLFormatForImage(mUpdateFormat),
mUpdateRect.width,
mUpdateRect.height,
0,
GLFormatForImage(uploadImage->GetFormat()),
GLTypeForImage(uploadImage->GetFormat()),
uploadImage->GetData());
} else {
mGLContext->fTexSubImage2D(LOCAL_GL_TEXTURE_2D,
0,
mUpdateRect.x,
mUpdateRect.y,
mUpdateRect.width,
mUpdateRect.height,
GLFormatForImage(uploadImage->GetFormat()),
GLTypeForImage(uploadImage->GetFormat()),
uploadImage->GetData());
}
mUpdateDrawTarget = nullptr;
mTextureState = Valid;
return; // mTexture is bound
}
bool
TextureImageEGL::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom /* = gfx::IntPoint(0,0) */)
{
@ -214,10 +115,10 @@ TextureImageEGL::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion&
aSurf,
region,
mTexture,
mSize,
&uploadSize,
needInit,
bounds.TopLeft() + gfx::IntPoint(aFrom.x, aFrom.y),
false);
aFrom);
if (uploadSize > 0) {
UpdateUploadSize(uploadSize);
}
@ -242,8 +143,6 @@ TextureImageEGL::BindTexture(GLenum aTextureUnit)
void
TextureImageEGL::Resize(const gfx::IntSize& aSize)
{
NS_ASSERTION(!mUpdateDrawTarget, "Resize() while in update?");
if (mSize == aSize && mTextureState != Created)
return;

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

@ -26,12 +26,6 @@ public:
virtual ~TextureImageEGL();
virtual void GetUpdateRegion(nsIntRegion& aForRegion);
virtual gfx::DrawTarget* BeginUpdate(nsIntRegion& aRegion);
virtual void EndUpdate();
virtual bool DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom = gfx::IntPoint(0,0));
virtual void BindTexture(GLenum aTextureUnit);
@ -45,8 +39,6 @@ public:
return mTexture;
};
virtual bool InUpdate() const { return !!mUpdateDrawTarget; }
virtual void Resize(const gfx::IntSize& aSize);
bool BindTexImage();
@ -65,9 +57,7 @@ protected:
GLContext* mGLContext;
gfx::IntRect mUpdateRect;
gfx::SurfaceFormat mUpdateFormat;
RefPtr<gfx::DrawTarget> mUpdateDrawTarget;
EGLImage mEGLImage;
GLuint mTexture;
EGLSurface mSurface;

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

@ -94,7 +94,6 @@ if gl_provider == 'CGL':
# These files include Mac headers that are unfriendly to unified builds
SOURCES += [
"GLContextProviderCGL.mm",
"TextureImageCGL.mm"
]
EXPORTS += [
'GLContextCGL.h',

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

@ -171,16 +171,9 @@ UseTileTexture(CompositableTextureHostRef& aTexture,
}
if (!aUpdateRect.IsEmpty()) {
#ifdef MOZ_GFX_OPTIMIZE_MOBILE
aTexture->Updated(nullptr);
#else
// We possibly upload the entire texture contents here. This is a purposeful
// decision, as sub-image upload can often be slow and/or unreliable, but
// we may want to reevaluate this in the future.
// For !HasIntermediateBuffer() textures, this is likely a no-op.
nsIntRegion region = aUpdateRect;
aTexture->Updated(&region);
#endif
}
aTexture->PrepareTextureSource(aTextureSource);

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

@ -42,8 +42,6 @@ GLBlitTextureImageHelper::BlitTextureImage(TextureImage *aSrc, const gfx::IntRec
TextureImage *aDst, const gfx::IntRect& aDstRect)
{
GLContext *gl = mCompositor->gl();
NS_ASSERTION(!aSrc->InUpdate(), "Source texture is in update!");
NS_ASSERTION(!aDst->InUpdate(), "Destination texture is in update!");
if (!aSrc || !aDst || aSrcRect.IsEmpty() || aDstRect.IsEmpty())
return;

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

@ -193,9 +193,6 @@ TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface,
mTexImage->UpdateFromDataSource(aSurface, aDestRegion, aSrcOffset);
if (mTexImage->InUpdate()) {
mTexImage->EndUpdate();
}
return true;
}

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

@ -31,6 +31,28 @@ struct gfxQuaternion : public mozilla::gfx::BasePoint4D<gfxFloat, gfxQuaternion>
z = -z;
}
// Convert from |direction axis, angle| pair to gfxQuaternion.
//
// Reference:
// https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation
//
// if the direction axis is (x, y, z) = xi + yj + zk,
// and the angle is |theta|, this formula can be done using
// an extension of Euler's formula:
// q = cos(theta/2) + (xi + yj + zk)(sin(theta/2))
// = cos(theta/2) +
// x*sin(theta/2)i + y*sin(theta/2)j + z*sin(theta/2)k
// Note: aDirection should be an unit vector and
// the unit of aAngle should be Radian.
gfxQuaternion(const mozilla::gfx::Point3D &aDirection, gfxFloat aAngle) {
MOZ_ASSERT(mozilla::gfx::FuzzyEqual(aDirection.Length(), 1.0f),
"aDirection should be an unit vector");
x = aDirection.x * sin(aAngle/2.0);
y = aDirection.y * sin(aAngle/2.0);
z = aDirection.z * sin(aAngle/2.0);
w = cos(aAngle/2.0);
}
gfxQuaternion Slerp(const gfxQuaternion &aOther, gfxFloat aCoeff) {
gfxFloat dot = mozilla::clamped(DotProduct(aOther), -1.0, 1.0);
if (dot == 1.0) {

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

@ -89,3 +89,15 @@ VRControllerManager::NewButtonEvent(uint32_t aIndex, uint32_t aButton,
MOZ_ASSERT(vm);
vm->NotifyGamepadChange<dom::GamepadButtonInformation>(a);
}
void
VRControllerManager::NewAxisMove(uint32_t aIndex, uint32_t aAxis,
double aValue)
{
dom::GamepadAxisInformation a(aIndex, dom::GamepadServiceType::VR,
aAxis, aValue);
VRManager* vm = VRManager::Get();
MOZ_ASSERT(vm);
vm->NotifyGamepadChange<dom::GamepadAxisInformation>(a);
}

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

@ -252,6 +252,7 @@ public:
virtual void GetControllers(nsTArray<RefPtr<VRControllerHost>>& aControllerResult) = 0;
virtual void ScanForDevices() = 0;
void NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed);
void NewAxisMove(uint32_t aIndex, uint32_t aAxis, double aValue);
void AddGamepad(const char* aID, dom::GamepadMappingType aMapping,
uint32_t aNumButtons, uint32_t aNumAxes);
@ -266,6 +267,8 @@ protected:
private:
virtual void HandleButtonPress(uint32_t aControllerIdx,
uint64_t aButtonPressed) = 0;
virtual void HandleAxisMove(uint32_t aControllerIdx, uint32_t aAxis,
float aValue) = 0;
};
} // namespace gfx

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

@ -72,16 +72,24 @@ const uint64_t gOpenVRButtonMask[] = {
const uint32_t gNumOpenVRButtonMask = sizeof(gOpenVRButtonMask) /
sizeof(uint64_t);
const uint64_t gOpenVRAxisMask[] = {
vr::ButtonMaskFromId(vr::EVRButtonId::k_EButton_Axis0),
vr::ButtonMaskFromId(vr::EVRButtonId::k_EButton_Axis1),
vr::ButtonMaskFromId(vr::EVRButtonId::k_EButton_Axis2),
vr::ButtonMaskFromId(vr::EVRButtonId::k_EButton_Axis3),
vr::ButtonMaskFromId(vr::EVRButtonId::k_EButton_Axis4)
enum class VRControllerAxisType : uint16_t {
TrackpadXAxis,
TrackpadYAxis,
Trigger,
NumVRControllerAxisType
};
const uint32_t gNumOpenVRAxisMask = sizeof(gOpenVRAxisMask) /
sizeof(uint64_t);
#define VRControllerAxis(aButtonId) (aButtonId - vr::EVRButtonId::k_EButton_Axis0)
const uint32_t gOpenVRAxes[] = {
VRControllerAxis(vr::EVRButtonId::k_EButton_Axis0),
VRControllerAxis(vr::EVRButtonId::k_EButton_Axis0),
VRControllerAxis(vr::EVRButtonId::k_EButton_Axis1)
};
const uint32_t gNumOpenVRAxis = sizeof(gOpenVRAxes) /
sizeof(uint32_t);
bool
LoadOpenVRRuntime()
@ -479,7 +487,7 @@ VRControllerOpenVR::VRControllerOpenVR()
mControllerInfo.mControllerName.AssignLiteral("OpenVR HMD");
mControllerInfo.mMappingType = dom::GamepadMappingType::_empty;
mControllerInfo.mNumButtons = gNumOpenVRButtonMask;
mControllerInfo.mNumAxes = gNumOpenVRAxisMask;
mControllerInfo.mNumAxes = gNumOpenVRAxis;
}
VRControllerOpenVR::~VRControllerOpenVR()
@ -559,6 +567,7 @@ VRControllerManagerOpenVR::HandleInput()
{
RefPtr<impl::VRControllerOpenVR> controller;
vr::VRControllerState_t state;
uint32_t axis = 0;
if (!mOpenVRInstalled) {
return;
@ -578,7 +587,17 @@ VRControllerManagerOpenVR::HandleInput()
HandleButtonPress(controller->GetIndex(), state.ulButtonPressed);
}
// Handle Axis support in Bug 1299930
axis = static_cast<uint32_t>(VRControllerAxisType::TrackpadXAxis);
HandleAxisMove(controller->GetIndex(), axis,
state.rAxis[gOpenVRAxes[axis]].x);
axis = static_cast<uint32_t>(VRControllerAxisType::TrackpadYAxis);
HandleAxisMove(controller->GetIndex(), axis,
state.rAxis[gOpenVRAxes[axis]].y);
axis = static_cast<uint32_t>(VRControllerAxisType::Trigger);
HandleAxisMove(controller->GetIndex(), axis,
state.rAxis[gOpenVRAxes[axis]].x);
}
}
}
@ -595,6 +614,15 @@ VRControllerManagerOpenVR::HandleButtonPress(uint32_t aControllerIdx,
}
}
void
VRControllerManagerOpenVR::HandleAxisMove(uint32_t aControllerIdx, uint32_t aAxis,
float aValue)
{
if (aValue != 0.0f) {
NewAxisMove(aControllerIdx, aAxis, aValue);
}
}
void
VRControllerManagerOpenVR::GetControllers(nsTArray<RefPtr<VRControllerHost>>& aControllerResult)
{
@ -635,7 +663,7 @@ VRControllerManagerOpenVR::ScanForDevices()
// Not already present, add it.
AddGamepad("OpenVR Gamepad", GamepadMappingType::_empty,
gNumOpenVRButtonMask, gNumOpenVRAxisMask);
gNumOpenVRButtonMask, gNumOpenVRAxis);
++mControllerCount;
}
}

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

@ -122,6 +122,8 @@ private:
virtual void HandleButtonPress(uint32_t aControllerIdx,
uint64_t aButtonPressed) override;
virtual void HandleAxisMove(uint32_t aControllerIdx, uint32_t aAxis,
float aValue) override;
bool mOpenVRInstalled;
nsTArray<RefPtr<impl::VRControllerOpenVR>> mOpenVRController;

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -87,6 +87,8 @@ public:
* should be calculated.
* @param aEndValue The end of the interval for which the distance
* should be calculated.
* @param aStyleContext The style context to use for processing the
* translate part of transforms.
* @param aDistance The result of the calculation.
* @return true on success, false on failure.
*/
@ -94,6 +96,7 @@ public:
ComputeDistance(nsCSSPropertyID aProperty,
const StyleAnimationValue& aStartValue,
const StyleAnimationValue& aEndValue,
nsStyleContext* aStyleContext,
double& aDistance);
/**

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

@ -16,6 +16,7 @@
#include "nsCSSKeywords.h"
#include "mozilla/StyleAnimationValue.h"
#include "gfxMatrix.h"
#include "gfxQuaternion.h"
#include <limits>
@ -176,7 +177,7 @@ ProcessTranslatePart(const nsCSSValue& aValue,
nsPresContext::AppUnitsPerCSSPixel());
// We want to avoid calling aDimensionGetter if there's no percentage to be
// resolved (for performance reasons - see TransformReferenceBox).
if (percent != 0.0f && aRefBox) {
if (percent != 0.0f && aRefBox && !aRefBox->IsEmpty()) {
translation += percent *
NSAppUnitsToFloatPixels((aRefBox->*aDimensionGetter)(),
nsPresContext::AppUnitsPerCSSPixel());
@ -224,7 +225,7 @@ ProcessMatrix(Matrix4x4& aMatrix,
aMatrix = result * aMatrix;
}
static void
static void
ProcessMatrix3D(Matrix4x4& aMatrix,
const nsCSSValue::Array* aData,
nsStyleContext* aContext,
@ -335,7 +336,7 @@ ProcessTranslateY(Matrix4x4& aMatrix,
aMatrix.PreTranslate(temp);
}
static void
static void
ProcessTranslateZ(Matrix4x4& aMatrix,
const nsCSSValue::Array* aData,
nsStyleContext* aContext,
@ -408,8 +409,8 @@ ProcessTranslate3D(Matrix4x4& aMatrix,
/* Helper function to set up a scale matrix. */
static void
ProcessScaleHelper(Matrix4x4& aMatrix,
float aXScale,
float aYScale,
float aXScale,
float aYScale,
float aZScale)
{
aMatrix.PreScale(aXScale, aYScale, aZScale);
@ -460,7 +461,7 @@ ProcessScale(Matrix4x4& aMatrix, const nsCSSValue::Array* aData)
const nsCSSValue& scaleY = (aData->Count() == 2 ? scaleX :
aData->Item(2));
ProcessScaleHelper(aMatrix,
ProcessScaleHelper(aMatrix,
scaleX.GetFloatValue(),
scaleY.GetFloatValue(),
1.0f);
@ -545,7 +546,7 @@ ProcessRotate3D(Matrix4x4& aMatrix, const nsCSSValue::Array* aData)
aMatrix = temp * aMatrix;
}
static void
static void
ProcessPerspective(Matrix4x4& aMatrix,
const nsCSSValue::Array* aData,
nsStyleContext *aContext,
@ -666,7 +667,7 @@ MatrixForTransformFunction(Matrix4x4& aMatrix,
break;
case eCSSKeyword_perspective:
*aContains3dTransform = true;
ProcessPerspective(aMatrix, aData, aContext, aPresContext,
ProcessPerspective(aMatrix, aData, aContext, aPresContext,
aConditions);
break;
default:
@ -685,6 +686,32 @@ TransformFunctionOf(const nsCSSValue::Array* aData)
return aData->Item(0).GetKeywordValue();
}
void
SetIdentityMatrix(nsCSSValue::Array* aMatrix)
{
MOZ_ASSERT(aMatrix, "aMatrix should be non-null");
nsCSSKeyword tfunc = TransformFunctionOf(aMatrix);
MOZ_ASSERT(tfunc == eCSSKeyword_matrix ||
tfunc == eCSSKeyword_matrix3d,
"Only accept matrix and matrix3d");
if (tfunc == eCSSKeyword_matrix) {
MOZ_ASSERT(aMatrix->Count() == 7, "Invalid matrix");
Matrix m;
for (size_t i = 0; i < 6; ++i) {
aMatrix->Item(i + 1).SetFloatValue(m.components[i], eCSSUnit_Number);
}
return;
}
MOZ_ASSERT(aMatrix->Count() == 17, "Invalid matrix3d");
Matrix4x4 m;
for (size_t i = 0; i < 16; ++i) {
aMatrix->Item(i + 1).SetFloatValue(m.components[i], eCSSUnit_Number);
}
}
Matrix4x4
ReadTransforms(const nsCSSValueList* aList,
nsStyleContext* aContext,
@ -721,4 +748,318 @@ ReadTransforms(const nsCSSValueList* aList,
return result;
}
/*
* The relevant section of the transitions specification:
* http://dev.w3.org/csswg/css3-transitions/#animation-of-property-types-
* defers all of the details to the 2-D and 3-D transforms specifications.
* For the 2-D transforms specification (all that's relevant for us, right
* now), the relevant section is:
* http://dev.w3.org/csswg/css3-2d-transforms/#animation
* This, in turn, refers to the unmatrix program in Graphics Gems,
* available from http://tog.acm.org/resources/GraphicsGems/ , and in
* particular as the file GraphicsGems/gemsii/unmatrix.c
* in http://tog.acm.org/resources/GraphicsGems/AllGems.tar.gz
*
* The unmatrix reference is for general 3-D transform matrices (any of the
* 16 components can have any value).
*
* For CSS 2-D transforms, we have a 2-D matrix with the bottom row constant:
*
* [ A C E ]
* [ B D F ]
* [ 0 0 1 ]
*
* For that case, I believe the algorithm in unmatrix reduces to:
*
* (1) If A * D - B * C == 0, the matrix is singular. Fail.
*
* (2) Set translation components (Tx and Ty) to the translation parts of
* the matrix (E and F) and then ignore them for the rest of the time.
* (For us, E and F each actually consist of three constants: a
* length, a multiplier for the width, and a multiplier for the
* height. This actually requires its own decomposition, but I'll
* keep that separate.)
*
* (3) Let the X scale (Sx) be sqrt(A^2 + B^2). Then divide both A and B
* by it.
*
* (4) Let the XY shear (K) be A * C + B * D. From C, subtract A times
* the XY shear. From D, subtract B times the XY shear.
*
* (5) Let the Y scale (Sy) be sqrt(C^2 + D^2). Divide C, D, and the XY
* shear (K) by it.
*
* (6) At this point, A * D - B * C is either 1 or -1. If it is -1,
* negate the XY shear (K), the X scale (Sx), and A, B, C, and D.
* (Alternatively, we could negate the XY shear (K) and the Y scale
* (Sy).)
*
* (7) Let the rotation be R = atan2(B, A).
*
* Then the resulting decomposed transformation is:
*
* translate(Tx, Ty) rotate(R) skewX(atan(K)) scale(Sx, Sy)
*
* An interesting result of this is that all of the simple transform
* functions (i.e., all functions other than matrix()), in isolation,
* decompose back to themselves except for:
* 'skewY(φ)', which is 'matrix(1, tan(φ), 0, 1, 0, 0)', which decomposes
* to 'rotate(φ) skewX(φ) scale(sec(φ), cos(φ))' since (ignoring the
* alternate sign possibilities that would get fixed in step 6):
* In step 3, the X scale factor is sqrt(1+tan²(φ)) = sqrt(sec²(φ)) = sec(φ).
* Thus, after step 3, A = 1/sec(φ) = cos(φ) and B = tan(φ) / sec(φ) = sin(φ).
* In step 4, the XY shear is sin(φ).
* Thus, after step 4, C = -cos(φ)sin(φ) and D = 1 - sin²(φ) = cos²(φ).
* Thus, in step 5, the Y scale is sqrt(cos²(φ)(sin²(φ) + cos²(φ)) = cos(φ).
* Thus, after step 5, C = -sin(φ), D = cos(φ), and the XY shear is tan(φ).
* Thus, in step 6, A * D - B * C = cos²(φ) + sin²(φ) = 1.
* In step 7, the rotation is thus φ.
*
* skew(θ, φ), which is matrix(1, tan(φ), tan(θ), 1, 0, 0), which decomposes
* to 'rotate(φ) skewX(θ + φ) scale(sec(φ), cos(φ))' since (ignoring
* the alternate sign possibilities that would get fixed in step 6):
* In step 3, the X scale factor is sqrt(1+tan²(φ)) = sqrt(sec²(φ)) = sec(φ).
* Thus, after step 3, A = 1/sec(φ) = cos(φ) and B = tan(φ) / sec(φ) = sin(φ).
* In step 4, the XY shear is cos(φ)tan(θ) + sin(φ).
* Thus, after step 4,
* C = tan(θ) - cos(φ)(cos(φ)tan(θ) + sin(φ)) = tan(θ)sin²(φ) - cos(φ)sin(φ)
* D = 1 - sin(φ)(cos(φ)tan(θ) + sin(φ)) = cos²(φ) - sin(φ)cos(φ)tan(θ)
* Thus, in step 5, the Y scale is sqrt(C² + D²) =
* sqrt(tan²(θ)(sin(φ) + sin²(φ)cos²(φ)) -
* 2 tan(θ)(sin³(φ)cos(φ) + sin(φ)cos³(φ)) +
* (sin²(φ)cos²(φ) + cos(φ))) =
* sqrt(tan²(θ)sin²(φ) - 2 tan(θ)sin(φ)cos(φ) + cos²(φ)) =
* cos(φ) - tan(θ)sin(φ) (taking the negative of the obvious solution so
* we avoid flipping in step 6).
* After step 5, C = -sin(φ) and D = cos(φ), and the XY shear is
* (cos(φ)tan(θ) + sin(φ)) / (cos(φ) - tan(θ)sin(φ)) =
* (dividing both numerator and denominator by cos(φ))
* (tan(θ) + tan(φ)) / (1 - tan(θ)tan(φ)) = tan(θ + φ).
* (See http://en.wikipedia.org/wiki/List_of_trigonometric_identities .)
* Thus, in step 6, A * D - B * C = cos²(φ) + sin²(φ) = 1.
* In step 7, the rotation is thus φ.
*
* To check this result, we can multiply things back together:
*
* [ cos(φ) -sin(φ) ] [ 1 tan(θ + φ) ] [ sec(φ) 0 ]
* [ sin(φ) cos(φ) ] [ 0 1 ] [ 0 cos(φ) ]
*
* [ cos(φ) cos(φ)tan(θ + φ) - sin(φ) ] [ sec(φ) 0 ]
* [ sin(φ) sin(φ)tan(θ + φ) + cos(φ) ] [ 0 cos(φ) ]
*
* but since tan(θ + φ) = (tan(θ) + tan(φ)) / (1 - tan(θ)tan(φ)),
* cos(φ)tan(θ + φ) - sin(φ)
* = cos(φ)(tan(θ) + tan(φ)) - sin(φ) + sin(φ)tan(θ)tan(φ)
* = cos(φ)tan(θ) + sin(φ) - sin(φ) + sin(φ)tan(θ)tan(φ)
* = cos(φ)tan(θ) + sin(φ)tan(θ)tan(φ)
* = tan(θ) (cos(φ) + sin(φ)tan(φ))
* = tan(θ) sec(φ) (cos²(φ) + sin²(φ))
* = tan(θ) sec(φ)
* and
* sin(φ)tan(θ + φ) + cos(φ)
* = sin(φ)(tan(θ) + tan(φ)) + cos(φ) - cos(φ)tan(θ)tan(φ)
* = tan(θ) (sin(φ) - sin(φ)) + sin(φ)tan(φ) + cos(φ)
* = sec(φ) (sin²(φ) + cos²(φ))
* = sec(φ)
* so the above is:
* [ cos(φ) tan(θ) sec(φ) ] [ sec(φ) 0 ]
* [ sin(φ) sec(φ) ] [ 0 cos(φ) ]
*
* [ 1 tan(θ) ]
* [ tan(φ) 1 ]
*/
/*
* Decompose2DMatrix implements the above decomposition algorithm.
*/
bool
Decompose2DMatrix(const Matrix& aMatrix,
Point3D& aScale,
ShearArray& aShear,
gfxQuaternion& aRotate,
Point3D& aTranslate)
{
float A = aMatrix._11,
B = aMatrix._12,
C = aMatrix._21,
D = aMatrix._22;
if (A * D == B * C) {
// singular matrix
return false;
}
float scaleX = sqrt(A * A + B * B);
A /= scaleX;
B /= scaleX;
float XYshear = A * C + B * D;
C -= A * XYshear;
D -= B * XYshear;
float scaleY = sqrt(C * C + D * D);
C /= scaleY;
D /= scaleY;
XYshear /= scaleY;
// A*D - B*C should now be 1 or -1
NS_ASSERTION(0.99 < Abs(A*D - B*C) && Abs(A*D - B*C) < 1.01,
"determinant should now be 1 or -1");
if (A * D < B * C) {
A = -A;
B = -B;
C = -C;
D = -D;
XYshear = -XYshear;
scaleX = -scaleX;
}
float rotate = atan2f(B, A);
aRotate = gfxQuaternion(0, 0, sin(rotate/2), cos(rotate/2));
aShear[ShearType::XYSHEAR] = XYshear;
aScale.x = scaleX;
aScale.y = scaleY;
aTranslate.x = aMatrix._31;
aTranslate.y = aMatrix._32;
return true;
}
/**
* Implementation of the unmatrix algorithm, specified by:
*
* http://dev.w3.org/csswg/css3-2d-transforms/#unmatrix
*
* This, in turn, refers to the unmatrix program in Graphics Gems,
* available from http://tog.acm.org/resources/GraphicsGems/ , and in
* particular as the file GraphicsGems/gemsii/unmatrix.c
* in http://tog.acm.org/resources/GraphicsGems/AllGems.tar.gz
*/
bool
Decompose3DMatrix(const Matrix4x4& aMatrix,
Point3D& aScale,
ShearArray& aShear,
gfxQuaternion& aRotate,
Point3D& aTranslate,
Point4D& aPerspective)
{
Matrix4x4 local = aMatrix;
if (local[3][3] == 0) {
return false;
}
/* Normalize the matrix */
local.Normalize();
/**
* perspective is used to solve for perspective, but it also provides
* an easy way to test for singularity of the upper 3x3 component.
*/
Matrix4x4 perspective = local;
Point4D empty(0, 0, 0, 1);
perspective.SetTransposedVector(3, empty);
if (perspective.Determinant() == 0.0) {
return false;
}
/* First, isolate perspective. */
if (local[0][3] != 0 || local[1][3] != 0 ||
local[2][3] != 0) {
/* aPerspective is the right hand side of the equation. */
aPerspective = local.TransposedVector(3);
/**
* Solve the equation by inverting perspective and multiplying
* aPerspective by the inverse.
*/
perspective.Invert();
aPerspective = perspective.TransposeTransform4D(aPerspective);
/* Clear the perspective partition */
local.SetTransposedVector(3, empty);
} else {
aPerspective = Point4D(0, 0, 0, 1);
}
/* Next take care of translation */
for (int i = 0; i < 3; i++) {
aTranslate[i] = local[3][i];
local[3][i] = 0;
}
/* Now get scale and shear. */
/* Compute X scale factor and normalize first row. */
aScale.x = local[0].Length();
local[0] /= aScale.x;
/* Compute XY shear factor and make 2nd local orthogonal to 1st. */
aShear[ShearType::XYSHEAR] = local[0].DotProduct(local[1]);
local[1] -= local[0] * aShear[ShearType::XYSHEAR];
/* Now, compute Y scale and normalize 2nd local. */
aScale.y = local[1].Length();
local[1] /= aScale.y;
aShear[ShearType::XYSHEAR] /= aScale.y;
/* Compute XZ and YZ shears, make 3rd local orthogonal */
aShear[ShearType::XZSHEAR] = local[0].DotProduct(local[2]);
local[2] -= local[0] * aShear[ShearType::XZSHEAR];
aShear[ShearType::YZSHEAR] = local[1].DotProduct(local[2]);
local[2] -= local[1] * aShear[ShearType::YZSHEAR];
/* Next, get Z scale and normalize 3rd local. */
aScale.z = local[2].Length();
local[2] /= aScale.z;
aShear[ShearType::XZSHEAR] /= aScale.z;
aShear[ShearType::YZSHEAR] /= aScale.z;
/**
* At this point, the matrix (in locals) is orthonormal.
* Check for a coordinate system flip. If the determinant
* is -1, then negate the matrix and the scaling factors.
*/
if (local[0].DotProduct(local[1].CrossProduct(local[2])) < 0) {
aScale *= -1;
for (int i = 0; i < 3; i++) {
local[i] *= -1;
}
}
/* Now, get the rotations out */
aRotate = gfxQuaternion(local);
return true;
}
Matrix
CSSValueArrayTo2DMatrix(nsCSSValue::Array* aArray)
{
MOZ_ASSERT(aArray &&
TransformFunctionOf(aArray) == eCSSKeyword_matrix &&
aArray->Count() == 7);
Matrix m(aArray->Item(1).GetFloatValue(),
aArray->Item(2).GetFloatValue(),
aArray->Item(3).GetFloatValue(),
aArray->Item(4).GetFloatValue(),
aArray->Item(5).GetFloatValue(),
aArray->Item(6).GetFloatValue());
return m;
}
Matrix4x4
CSSValueArrayTo3DMatrix(nsCSSValue::Array* aArray)
{
MOZ_ASSERT(aArray &&
TransformFunctionOf(aArray) == eCSSKeyword_matrix3d &&
aArray->Count() == 17);
gfx::Float array[16];
for (size_t i = 0; i < 16; ++i) {
array[i] = aArray->Item(i+1).GetFloatValue();
}
Matrix4x4 m(array);
return m;
}
} // namespace nsStyleTransformMatrix

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

@ -10,11 +10,13 @@
#ifndef nsStyleTransformMatrix_h_
#define nsStyleTransformMatrix_h_
#include "mozilla/EnumeratedArray.h"
#include "nsCSSValue.h"
class nsIFrame;
class nsStyleContext;
class nsPresContext;
struct gfxQuaternion;
struct nsRect;
namespace mozilla {
class RuleNodeCacheConditions;
@ -108,6 +110,10 @@ namespace nsStyleTransformMatrix {
return mHeight;
}
bool IsEmpty() {
return !mFrame;
}
private:
// We don't really need to prevent copying, but since none of our consumers
// currently need to copy, preventing copying may allow us to catch some
@ -127,6 +133,8 @@ namespace nsStyleTransformMatrix {
*/
nsCSSKeyword TransformFunctionOf(const nsCSSValue::Array* aData);
void SetIdentityMatrix(nsCSSValue::Array* aMatrix);
float ProcessTranslatePart(const nsCSSValue& aValue,
nsStyleContext* aContext,
nsPresContext* aPresContext,
@ -169,6 +177,37 @@ namespace nsStyleTransformMatrix {
TransformReferenceBox& aBounds,
float aAppUnitsPerMatrixUnit,
bool* aContains3dTransform);
// Shear type for decomposition.
enum class ShearType {
XYSHEAR,
XZSHEAR,
YZSHEAR,
Count
};
using ShearArray =
mozilla::EnumeratedArray<ShearType, ShearType::Count, float>;
/*
* Implements the 2d transform matrix decomposition algorithm.
*/
bool Decompose2DMatrix(const mozilla::gfx::Matrix& aMatrix,
mozilla::gfx::Point3D& aScale,
ShearArray& aShear,
gfxQuaternion& aRotate,
mozilla::gfx::Point3D& aTranslate);
/*
* Implements the 3d transform matrix decomposition algorithm.
*/
bool Decompose3DMatrix(const mozilla::gfx::Matrix4x4& aMatrix,
mozilla::gfx::Point3D& aScale,
ShearArray& aShear,
gfxQuaternion& aRotate,
mozilla::gfx::Point3D& aTranslate,
mozilla::gfx::Point4D& aPerspective);
mozilla::gfx::Matrix CSSValueArrayTo2DMatrix(nsCSSValue::Array* aArray);
mozilla::gfx::Matrix4x4 CSSValueArrayTo3DMatrix(nsCSSValue::Array* aArray);
} // namespace nsStyleTransformMatrix
#endif

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

@ -535,9 +535,6 @@ NrIceCtx::Initialize(const std::string& ufrag,
NR_ICE_CTX_FLAGS_ANSWERER;
flags |= NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION;
switch (policy_) {
case ICE_POLICY_NONE:
MOZ_CRASH();
break;
case ICE_POLICY_RELAY:
flags |= NR_ICE_CTX_FLAGS_RELAY_ONLY;
break;
@ -837,9 +834,6 @@ abort:
nsresult NrIceCtx::StartGathering(bool default_route_only, bool proxy_only) {
ASSERT_ON_THREAD(sts_target_);
if (policy_ == ICE_POLICY_NONE) {
return NS_OK;
}
SetGatheringState(ICE_CTX_GATHER_STARTED);
if (default_route_only) {
@ -927,11 +921,6 @@ nsresult NrIceCtx::ParseGlobalAttributes(std::vector<std::string> attrs) {
nsresult NrIceCtx::StartChecks() {
int r;
if (policy_ == ICE_POLICY_NONE) {
MOZ_MTLOG(ML_ERROR, "Couldn't start peer checks because policy == none");
SetConnectionState(ICE_CTX_FAILED);
return NS_ERROR_FAILURE;
}
r=nr_ice_peer_ctx_pair_candidates(peer_);
if (r) {
MOZ_MTLOG(ML_ERROR, "Couldn't pair candidates on "

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

@ -209,8 +209,7 @@ class NrIceCtx {
ICE_CONTROLLED
};
enum Policy { ICE_POLICY_NONE,
ICE_POLICY_RELAY,
enum Policy { ICE_POLICY_RELAY,
ICE_POLICY_NO_HOST,
ICE_POLICY_ALL
};

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

@ -479,9 +479,6 @@ PeerConnectionConfiguration::Init(const RTCConfiguration& aSrc)
}
switch (aSrc.mIceTransportPolicy) {
case dom::RTCIceTransportPolicy::None:
setIceTransportPolicy(NrIceCtx::ICE_POLICY_NONE);
break;
case dom::RTCIceTransportPolicy::Relay:
setIceTransportPolicy(NrIceCtx::ICE_POLICY_RELAY);
break;

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

@ -49,7 +49,6 @@ import org.mozilla.gecko.GeckoAppShell.AppStateListener;
public class VideoCaptureAndroid implements PreviewCallback, Callback, AppStateListener {
private final static String TAG = "WEBRTC-JC";
private static SurfaceHolder localPreview;
// Only non-null while capturing, accessed exclusively from synchronized methods.
Camera camera;
private Camera.CameraInfo info;
@ -81,23 +80,13 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback, AppStateL
private int frameCount;
private int frameDropRatio;
// Requests future capturers to send their frames to |localPreview| directly.
public static void setLocalPreview(SurfaceHolder localPreview) {
// It is a gross hack that this is a class-static. Doing it right would
// mean plumbing this through the C++ API and using it from
// webrtc/examples/android/media_demo's MediaEngine class.
VideoCaptureAndroid.localPreview = localPreview;
}
@WebRTCJNITarget
public VideoCaptureAndroid(int id, long native_capturer) {
this.id = id;
this.native_capturer = native_capturer;
this.context = GetContext();
if(android.os.Build.VERSION.SDK_INT>8) {
this.info = new Camera.CameraInfo();
Camera.getCameraInfo(id, info);
}
this.info = new Camera.CameraInfo();
Camera.getCameraInfo(id, info);
mCaptureRotation = GetRotateAmount();
}
@ -133,21 +122,13 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback, AppStateL
case Surface.ROTATION_180: degrees = 180; break;
case Surface.ROTATION_270: degrees = 270; break;
}
if(android.os.Build.VERSION.SDK_INT>8) {
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
return result;
} else {
// Assume 90deg orientation for Froyo devices.
// Only back-facing cameras are supported in Froyo.
int orientation = 90;
int result = (orientation - degrees + 360) % 360;
return result;
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
return result;
}
// Return the global application context.
@ -203,51 +184,34 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback, AppStateL
}
Throwable error = null;
try {
if(android.os.Build.VERSION.SDK_INT>8) {
camera = Camera.open(id);
} else {
camera = Camera.open();
}
camera = Camera.open(id);
localPreview = ViERenderer.GetLocalRenderer();
if (localPreview != null) {
localPreview.addCallback(this);
if (localPreview.getSurface() != null &&
localPreview.getSurface().isValid()) {
camera.setPreviewDisplay(localPreview);
}
} else {
if(android.os.Build.VERSION.SDK_INT>10) {
// No local renderer (we only care about onPreviewFrame() buffers, not a
// directly-displayed UI element). Camera won't capture without
// setPreview{Texture,Display}, so we create a SurfaceTexture and hand
// it over to Camera, but never listen for frame-ready callbacks,
// and never call updateTexImage on it.
try {
cameraGlTextures = new int[1];
// No local renderer (we only care about onPreviewFrame() buffers, not a
// directly-displayed UI element). Camera won't capture without
// setPreview{Texture,Display}, so we create a SurfaceTexture and hand
// it over to Camera, but never listen for frame-ready callbacks,
// and never call updateTexImage on it.
try {
cameraGlTextures = new int[1];
// Generate one texture pointer and bind it as an external texture.
GLES20.glGenTextures(1, cameraGlTextures, 0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
cameraGlTextures[0]);
GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
// Generate one texture pointer and bind it as an external texture.
GLES20.glGenTextures(1, cameraGlTextures, 0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
cameraGlTextures[0]);
GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
cameraSurfaceTexture = new SurfaceTexture(cameraGlTextures[0]);
cameraSurfaceTexture.setOnFrameAvailableListener(null);
camera.setPreviewTexture(cameraSurfaceTexture);
} catch (IOException e) {
throw new RuntimeException(e);
}
} else {
throw new RuntimeException("No preview surface for Camera.");
}
cameraSurfaceTexture = new SurfaceTexture(cameraGlTextures[0]);
cameraSurfaceTexture.setOnFrameAvailableListener(null);
camera.setPreviewTexture(cameraSurfaceTexture);
} catch (IOException e) {
throw new RuntimeException(e);
}
Log.d(TAG, "Camera orientation: " + info.orientation +
@ -300,11 +264,7 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback, AppStateL
min_mfps *= frameDropRatio;
max_mfps *= frameDropRatio;
Log.d(TAG, "Camera preview mfps range: " + min_mfps + " - " + max_mfps);
if (android.os.Build.VERSION.SDK_INT>8) {
parameters.setPreviewFpsRange(min_mfps, max_mfps);
} else {
parameters.setPreviewFrameRate(max_mfps / 1000);
}
parameters.setPreviewFpsRange(min_mfps, max_mfps);
int format = ImageFormat.NV21;
parameters.setPreviewFormat(format);
@ -336,8 +296,6 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback, AppStateL
}
exchange(result, true);
return;
} catch (IOException e) {
error = e;
} catch (RuntimeException e) {
error = e;
}
@ -401,18 +359,11 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback, AppStateL
try {
camera.setPreviewCallbackWithBuffer(null);
camera.stopPreview();
if (localPreview != null) {
localPreview.removeCallback(this);
camera.setPreviewDisplay(null);
} else {
if(android.os.Build.VERSION.SDK_INT>10) {
camera.setPreviewTexture(null);
cameraSurfaceTexture = null;
if (cameraGlTextures != null) {
GLES20.glDeleteTextures(1, cameraGlTextures, 0);
cameraGlTextures = null;
}
}
camera.setPreviewTexture(null);
cameraSurfaceTexture = null;
if (cameraGlTextures != null) {
GLES20.glDeleteTextures(1, cameraGlTextures, 0);
cameraGlTextures = null;
}
camera.release();
camera = null;

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

@ -24,25 +24,6 @@ import org.mozilla.gecko.util.ThreadUtils;
public class ViERenderer {
private final static String TAG = "WEBRTC-ViEREnderer";
// View used for local rendering that Cameras can use for Video Overlay.
private static SurfaceHolder g_localRenderer;
public static SurfaceView CreateRenderer(Context context) {
return CreateRenderer(context, false);
}
public static SurfaceView CreateRenderer(Context context,
boolean useOpenGLES2) {
if(useOpenGLES2 == true && ViEAndroidGLES20.IsSupported(context))
return new ViEAndroidGLES20(context);
else
return new SurfaceView(context);
}
// Creates a SurfaceView to be used by Android Camera
// service to display a local preview.
// This needs to be used on Android prior to version 2.1
// in order to run the camera.
// Call this function before ViECapture::StartCapture.
// The created view needs to be added to a visible layout
// after a camera has been allocated
@ -53,19 +34,13 @@ public class ViERenderer {
// LinearLayout.addview
// ViECapture::StartCapture
public static void CreateLocalRenderer() {
View cameraView = GeckoAppShell.getGeckoInterface().getCameraView();
if (cameraView != null && (cameraView instanceof SurfaceView)) {
SurfaceView localRender = (SurfaceView)cameraView;
g_localRenderer = localRender.getHolder();
}
ThreadUtils.getUiHandler().post(new Runnable() {
@Override
public void run() {
try {
GeckoAppShell.getGeckoInterface().enableCameraView();
GeckoAppShell.getGeckoInterface().enableOrientationListener();
} catch (Exception e) {
Log.e(TAG, "CreateLocalRenderer enableCameraView exception: "
Log.e(TAG, "enableOrientationListener exception: "
+ e.getLocalizedMessage());
}
}
@ -73,26 +48,17 @@ public class ViERenderer {
}
public static void DestroyLocalRenderer() {
if (g_localRenderer != null) {
g_localRenderer = null;
ThreadUtils.getUiHandler().post(new Runnable() {
@Override
public void run() {
try {
GeckoAppShell.getGeckoInterface().disableCameraView();
} catch (Exception e) {
Log.e(TAG,
"DestroyLocalRenderer disableCameraView exception: " +
e.getLocalizedMessage());
}
ThreadUtils.getUiHandler().post(new Runnable() {
@Override
public void run() {
try {
GeckoAppShell.getGeckoInterface().disableOrientationListener();
} catch (Exception e) {
Log.e(TAG,
"disableOrientationListener exception: " +
e.getLocalizedMessage());
}
});
}
}
});
}
public static SurfaceHolder GetLocalRenderer() {
return g_localRenderer;
}
}

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

@ -171,7 +171,6 @@ public abstract class GeckoApp
protected RelativeLayout mMainLayout;
protected RelativeLayout mGeckoLayout;
private View mCameraView;
private OrientationEventListener mCameraOrientationEventListener;
public List<GeckoAppShell.AppStateListener> mAppStateListeners = new LinkedList<GeckoAppShell.AppStateListener>();
protected MenuPanel mMenuPanel;
@ -333,11 +332,6 @@ public abstract class GeckoApp
return this;
}
@Override
public View getCameraView() {
return mCameraView;
}
@Override
public void addAppStateListener(GeckoAppShell.AppStateListener listener) {
mAppStateListeners.add(listener);
@ -1847,7 +1841,7 @@ public abstract class GeckoApp
}
@Override
public void enableCameraView() {
public void enableOrientationListener() {
// Start listening for orientation events
mCameraOrientationEventListener = new OrientationEventListener(this) {
@Override
@ -1860,27 +1854,14 @@ public abstract class GeckoApp
}
};
mCameraOrientationEventListener.enable();
// Try to make it fully transparent.
if (mCameraView instanceof SurfaceView) {
mCameraView.setAlpha(0.0f);
ViewGroup mCameraLayout = (ViewGroup) findViewById(R.id.camera_layout);
// Some phones (eg. nexus S) need at least a 8x16 preview size
mCameraLayout.addView(mCameraView,
new AbsoluteLayout.LayoutParams(8, 16, 0, 0));
}
}
@Override
public void disableCameraView() {
public void disableOrientationListener() {
if (mCameraOrientationEventListener != null) {
mCameraOrientationEventListener.disable();
mCameraOrientationEventListener = null;
}
if (mCameraView != null) {
ViewGroup mCameraLayout = (ViewGroup) findViewById(R.id.camera_layout);
mCameraLayout.removeView(mCameraView);
}
}
@Override

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

@ -89,15 +89,6 @@ public abstract class AbstractTransactionalProvider extends ContentProvider {
*/
final ThreadLocal<Boolean> isInBatchOperation = new ThreadLocal<Boolean>();
/**
* Return true if OS version and database parallelism support indicates
* that this provider should bundle writes into transactions.
*/
@SuppressWarnings("static-method")
protected boolean shouldUseTransactions() {
return true;
}
private boolean isInBatch() {
final Boolean isInBatch = isInBatchOperation.get();
if (isInBatch == null) {
@ -116,7 +107,7 @@ public abstract class AbstractTransactionalProvider extends ContentProvider {
return;
}
if (shouldUseTransactions() && !db.inTransaction()) {
if (!db.inTransaction()) {
trace("beginWrite: beginning transaction.");
db.beginTransaction();
}
@ -132,7 +123,7 @@ public abstract class AbstractTransactionalProvider extends ContentProvider {
return;
}
if (shouldUseTransactions() && db.inTransaction()) {
if (db.inTransaction()) {
trace("Marking write transaction successful.");
db.setTransactionSuccessful();
}
@ -150,7 +141,7 @@ public abstract class AbstractTransactionalProvider extends ContentProvider {
return;
}
if (shouldUseTransactions() && db.inTransaction()) {
if (db.inTransaction()) {
trace("endWrite: ending transaction.");
db.endTransaction();
}

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

@ -19,6 +19,7 @@ import java.nio.ByteBuffer;
import java.util.LinkedList;
import java.util.NoSuchElementException;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
/* package */ final class Codec extends ICodec.Stub implements IBinder.DeathRecipient {
private static final String LOGTAG = "GeckoRemoteCodec";
@ -188,12 +189,13 @@ import java.util.Queue;
mAvailableInputBuffers.clear();
}
}
private volatile ICodecCallbacks mCallbacks;
private AsyncCodec mCodec;
private InputProcessor mInputProcessor;
private volatile boolean mFlushing = false;
private SamplePool mSamplePool;
private Queue<Sample> mSentOutputs = new LinkedList<>();
private Queue<Sample> mSentOutputs = new ConcurrentLinkedQueue<>();
public synchronized void setCallbacks(ICodecCallbacks callbacks) throws RemoteException {
mCallbacks = callbacks;
@ -345,8 +347,9 @@ import java.util.Queue;
public synchronized void releaseOutput(Sample sample) {
try {
mSamplePool.recycleOutput(mSentOutputs.remove());
} catch (NoSuchElementException e) {
Log.e(LOGTAG, "releaseOutput not found: " + sample + "sent: " + mSentOutputs);
} catch (Exception e) {
Log.e(LOGTAG, "failed to release output:" + sample);
e.printStackTrace();
}
sample.dispose();
}

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

@ -87,7 +87,15 @@ final class JellyBeanAsyncCodec implements AsyncCodec {
Message msg = obtainMessage(MSG_INPUT_BUFFER_AVAILABLE);
msg.arg1 = index;
sendMessage(msg);
processMessage(msg);
}
private void processMessage(Message msg) {
if (Looper.myLooper() == getLooper()) {
handleMessage(msg);
} else {
sendMessage(msg);
}
}
public void notifyOutputBuffer(int index, MediaCodec.BufferInfo info) {
@ -97,20 +105,19 @@ final class JellyBeanAsyncCodec implements AsyncCodec {
Message msg = obtainMessage(MSG_OUTPUT_BUFFER_AVAILABLE, info);
msg.arg1 = index;
sendMessage(msg);
processMessage(msg);
}
public void notifyOutputFormat(MediaFormat format) {
if (isCanceled()) {
return;
}
sendMessage(obtainMessage(MSG_OUTPUT_FORMAT_CHANGE, format));
processMessage(obtainMessage(MSG_OUTPUT_FORMAT_CHANGE, format));
}
public void notifyError(int result) {
Log.e(LOGTAG, "codec error:" + result);
sendMessage(obtainMessage(MSG_ERROR, result, 0));
processMessage(obtainMessage(MSG_ERROR, result, 0));
}
protected boolean handleMessageLocked(Message msg) {

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

@ -42,13 +42,6 @@
android:layout_height="match_parent"
android:visibility="gone"/>
<FrameLayout android:id="@+id/camera_layout"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true">
</FrameLayout>
<view class="org.mozilla.gecko.media.VideoPlayer" android:id="@+id/video_player"
android:layout_height="match_parent"
android:layout_width="match_parent">

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

@ -1,101 +0,0 @@
/* 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/. */
"use strict";
var ZoomHelper = {
zoomOut: function() {
Messaging.sendRequest({ type: "Browser:ZoomToPageWidth" });
},
isRectZoomedIn: function(aRect, aViewport) {
// This function checks to see if the area of the rect visible in the
// viewport (i.e. the "overlapArea" variable below) is approximately
// the max area of the rect we can show. It also checks that the rect
// is actually on-screen by testing the left and right edges of the rect.
// In effect, this tells us whether or not zooming in to this rect
// will significantly change what the user is seeing.
const minDifference = -20;
const maxDifference = 20;
const maxZoomAllowed = 4; // keep this in sync with mobile/android/base/ui/PanZoomController.MAX_ZOOM
let vRect = new Rect(aViewport.cssX, aViewport.cssY, aViewport.cssWidth, aViewport.cssHeight);
let overlap = vRect.intersect(aRect);
let overlapArea = overlap.width * overlap.height;
let availHeight = Math.min(aRect.width * vRect.height / vRect.width, aRect.height);
let showing = overlapArea / (aRect.width * availHeight);
let dw = (aRect.width - vRect.width);
let dx = (aRect.x - vRect.x);
if (fuzzyEquals(aViewport.zoom, maxZoomAllowed) && overlap.width / aRect.width > 0.9) {
// we're already at the max zoom and the block is not spilling off the side of the screen so that even
// if the block isn't taking up most of the viewport we can't pan/zoom in any more. return true so that we zoom out
return true;
}
return (showing > 0.9 &&
dx > minDifference && dx < maxDifference &&
dw > minDifference && dw < maxDifference);
},
/* Zoom to an element, optionally keeping a particular part of it
* in view if it is really tall.
*/
zoomToElement: function(aElement, aClickY = -1, aCanZoomOut = true, aCanScrollHorizontally = true) {
let rect = ElementTouchHelper.getBoundingContentRect(aElement);
const margin = 15;
let viewport = BrowserApp.selectedTab.getViewport();
rect = new Rect(aCanScrollHorizontally ? Math.max(viewport.cssPageLeft, rect.x - margin) : viewport.cssX,
rect.y,
aCanScrollHorizontally ? rect.w + 2 * margin : viewport.cssWidth,
rect.h);
// constrict the rect to the screen's right edge
rect.width = Math.min(rect.width, viewport.cssPageRight - rect.x);
// if the rect is already taking up most of the visible area and is stretching the
// width of the page, then we want to zoom out instead.
if (aElement) {
if (ZoomHelper.isRectZoomedIn(rect, viewport)) {
if (aCanZoomOut) {
ZoomHelper.zoomOut();
}
return;
}
ZoomHelper.zoomToRect(rect, aClickY);
}
},
/* Zoom to a specific part of the screen defined by a rect,
* optionally keeping a particular part of it in view
* if it is really tall.
*/
zoomToRect: function(aRect, aClickY = -1) {
let viewport = BrowserApp.selectedTab.getViewport();
let rect = {
x: aRect.x,
y: aRect.y,
w: aRect.width,
h: Math.min(aRect.width * viewport.cssHeight / viewport.cssWidth, aRect.height)
};
rect.type = "Browser:ZoomToRect";
if (aClickY >= 0) {
// if the block we're zooming to is really tall, and we want to keep a particular
// part of it in view, then adjust the y-coordinate of the target rect accordingly.
// the 1.2 multiplier is just a little fuzz to compensate for aRect including horizontal
// margins but not vertical ones.
let cssTapY = viewport.cssY + aClickY;
if ((aRect.height > rect.h) && (cssTapY > rect.y + (rect.h * 1.2))) {
rect.y = cssTapY - (rect.h / 2);
}
}
Messaging.sendRequest(rect);
},
};

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

@ -129,7 +129,6 @@ var lazilyLoadedBrowserScripts = [
["PluginHelper", "chrome://browser/content/PluginHelper.js"],
["OfflineApps", "chrome://browser/content/OfflineApps.js"],
["Linkifier", "chrome://browser/content/Linkify.js"],
["ZoomHelper", "chrome://browser/content/ZoomHelper.js"],
["CastingApps", "chrome://browser/content/CastingApps.js"],
["RemoteDebugger", "chrome://browser/content/RemoteDebugger.js"],
];
@ -4481,32 +4480,6 @@ var BrowserEventHandler = {
}
},
_handleTouchStart: function(aEvent) {
if (!BrowserApp.isBrowserContentDocumentDisplayed() || aEvent.touches.length > 1 || aEvent.defaultPrevented)
return;
let target = aEvent.target;
if (!target) {
return;
}
// If we've pressed a scrollable element, let Java know that we may
// want to override the scroll behaviour (for document sub-frames)
this._scrollableElement = this._findScrollableElement(target, true);
this._firstScrollEvent = true;
if (this._scrollableElement != null) {
// Discard if it's the top-level scrollable, we let Java handle this
// The top-level scrollable is the body in quirks mode and the html element
// in standards mode
let doc = BrowserApp.selectedBrowser.contentDocument;
let rootScrollable = (doc.compatMode === "BackCompat" ? doc.body : doc.documentElement);
if (this._scrollableElement != rootScrollable) {
Messaging.sendRequest({ type: "Panning:Override" });
}
}
},
_handleRetargetedTouchStart: function(aEvent) {
// we should only get this called just after a new touchstart with a single
// touch point.
@ -4610,45 +4583,6 @@ var BrowserEventHandler = {
});
},
onDoubleTap: function(aData) {
let metadata = ViewportHandler.getMetadataForDocument(BrowserApp.selectedBrowser.contentDocument);
if (metadata && !metadata.allowDoubleTapZoom) {
return;
}
let data = JSON.parse(aData);
let element = ElementTouchHelper.anyElementFromPoint(data.x, data.y);
if (!element) {
ZoomHelper.zoomOut();
return;
}
while (element && !this._shouldZoomToElement(element))
element = element.parentNode;
if (!element) {
ZoomHelper.zoomOut();
} else {
ZoomHelper.zoomToElement(element, data.y);
}
},
_shouldZoomToElement: function(aElement) {
let win = aElement.ownerDocument.defaultView;
if (win.getComputedStyle(aElement, null).display == "inline")
return false;
if (aElement instanceof Ci.nsIDOMHTMLLIElement)
return false;
if (aElement instanceof Ci.nsIDOMHTMLQuoteElement)
return false;
return true;
},
_firstScrollEvent: false,
_scrollableElement: null,
_highlightElement: null,
_doTapHighlight: function _doTapHighlight(aElement) {
@ -4660,137 +4594,10 @@ var BrowserEventHandler = {
return;
this._highlightElement = null;
},
_updateLastPosition: function(x, y, dx, dy) {
this.lastX = x;
this.lastY = y;
this.lastTime = Date.now();
this.motionBuffer.push({ dx: dx, dy: dy, time: this.lastTime });
},
_sendMouseEvent: function _sendMouseEvent(aName, aX, aY) {
let win = BrowserApp.selectedBrowser.contentWindow;
try {
let cwu = win.top.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
cwu.sendMouseEventToWindow(aName, aX, aY, 0, 1, 0, true, 0, Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH, false);
} catch(e) {
Cu.reportError(e);
}
},
_hasScrollableOverflow: function(elem) {
var win = elem.ownerDocument.defaultView;
if (!win)
return false;
var computedStyle = win.getComputedStyle(elem);
if (!computedStyle)
return false;
// We check for overflow:hidden only because all the other cases are scrollable
// under various conditions. See https://bugzilla.mozilla.org/show_bug.cgi?id=911574#c24
// for some more details.
return !(computedStyle.overflowX == 'hidden' && computedStyle.overflowY == 'hidden');
},
_findScrollableElement: function(elem, checkElem) {
// Walk the DOM tree until we find a scrollable element
let scrollable = false;
while (elem) {
/* Element is scrollable if its scroll-size exceeds its client size, and:
* - It has overflow other than 'hidden', or
* - It's a textarea node, or
* - It's a text input, or
* - It's a select element showing multiple rows
*/
if (checkElem) {
if ((elem.scrollTopMin != elem.scrollTopMax ||
elem.scrollLeftMin != elem.scrollLeftMax) &&
(this._hasScrollableOverflow(elem) ||
elem.matches("textarea")) ||
(elem instanceof HTMLInputElement && elem.mozIsTextField(false)) ||
(elem instanceof HTMLSelectElement && (elem.size > 1 || elem.multiple))) {
scrollable = true;
break;
}
} else {
checkElem = true;
}
// Propagate up iFrames
if (!elem.parentNode && elem.documentElement && elem.documentElement.ownerDocument)
elem = elem.documentElement.ownerDocument.defaultView.frameElement;
else
elem = elem.parentNode;
}
if (!scrollable)
return null;
return elem;
},
_scrollElementBy: function(elem, x, y) {
elem.scrollTop = elem.scrollTop + y;
elem.scrollLeft = elem.scrollLeft + x;
},
_elementCanScroll: function(elem, x, y) {
let scrollX = (x < 0 && elem.scrollLeft > 0)
|| (x > 0 && elem.scrollLeft < elem.scrollLeftMax);
let scrollY = (y < 0 && elem.scrollTop > 0)
|| (y > 0 && elem.scrollTop < elem.scrollTopMax);
return scrollX || scrollY;
}
};
const ElementTouchHelper = {
/* Return the element at the given coordinates, starting from the given window and
drilling down through frames. If no window is provided, the top-level window of
the currently selected tab is used. The coordinates provided should be CSS pixels
relative to the window's scroll position. */
anyElementFromPoint: function(aX, aY, aWindow) {
let win = (aWindow ? aWindow : BrowserApp.selectedBrowser.contentWindow);
let cwu = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
let elem = cwu.elementFromPoint(aX, aY, true, true);
while (elem && (elem instanceof HTMLIFrameElement || elem instanceof HTMLFrameElement)) {
let rect = elem.getBoundingClientRect();
aX -= rect.left;
aY -= rect.top;
cwu = elem.contentDocument.defaultView.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
elem = cwu.elementFromPoint(aX, aY, true, true);
}
return elem;
},
/* Returns the touch radius with zoom factored in. */
getTouchRadius: function getTouchRadius() {
let zoom = BrowserApp.selectedTab._zoom;
return {
top: this.radius.top / zoom,
right: this.radius.right / zoom,
bottom: this.radius.bottom / zoom,
left: this.radius.left / zoom
};
},
/* Returns the touch radius in device pixels. */
get radius() {
let mmToIn = 1 / 25.4;
let mmToPx = mmToIn * ViewportHandler.displayDPI;
let prefs = Services.prefs;
delete this.radius;
return this.radius = { "top": prefs.getIntPref("ui.touch.radius.topmm") * mmToPx,
"right": prefs.getIntPref("ui.touch.radius.rightmm") * mmToPx,
"bottom": prefs.getIntPref("ui.touch.radius.bottommm") * mmToPx,
"left": prefs.getIntPref("ui.touch.radius.leftmm") * mmToPx
};
},
getBoundingContentRect: function(aElement) {
if (!aElement)
return {x: 0, y: 0, w: 0, h: 0};
@ -5545,11 +5352,6 @@ var XPInstallObserver = {
};
var ViewportHandler = {
// The cached viewport metadata for each document. We tie viewport metadata to each document
// instead of to each tab so that we don't have to update it when the document changes. Using an
// ES6 weak map lets us avoid leaks.
_metadata: new WeakMap(),
init: function init() {
Services.obs.addObserver(this, "Window:Resize", false);
},
@ -5560,51 +5362,6 @@ var ViewportHandler = {
let windowUtils = window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
windowUtils.setNextPaintSyncId(scrollChange.id);
}
},
/**
* Returns true if a viewport tag was specified
*/
isViewportSpecified: function isViewportSpecified(aWindow) {
let tab = BrowserApp.getTabForWindow(aWindow);
let readerMode = false;
try {
readerMode = tab.browser.contentDocument.documentURI.startsWith("about:reader");
} catch (e) {
}
if (tab.desktopMode && !readerMode) {
return false;
}
let windowUtils = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
return !isNaN(parseFloat(windowUtils.getDocumentMetadata("viewport-initial-scale")))
|| !isNaN(parseFloat(windowUtils.getDocumentMetadata("viewport-minimum-scale")))
|| !isNaN(parseFloat(windowUtils.getDocumentMetadata("viewport-maximum-scale")))
|| ("" != windowUtils.getDocumentMetadata("viewport-user-scalable"))
|| ("" != windowUtils.getDocumentMetadata("viewport-width"))
|| ("" != windowUtils.getDocumentMetadata("viewport-height"));
},
get displayDPI() {
let utils = window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
delete this.displayDPI;
return this.displayDPI = utils.displayDPI;
},
/**
* Returns the viewport metadata for the given document, or undefined if there
* isn't one.
*/
getMetadataForDocument: function getMetadataForDocument(aDocument) {
return this._metadata.get(aDocument);
},
/** Updates the saved viewport metadata for the given content document. */
setMetadataForDocument: function setMetadataForDocument(aDocument, aMetadata) {
if (!aMetadata)
this._metadata.delete(aDocument);
else
this._metadata.set(aDocument, aMetadata);
}
};

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

@ -48,7 +48,6 @@ chrome.jar:
content/FeedHandler.js (content/FeedHandler.js)
content/Feedback.js (content/Feedback.js)
content/Linkify.js (content/Linkify.js)
content/ZoomHelper.js (content/ZoomHelper.js)
content/CastingApps.js (content/CastingApps.js)
content/RemoteDebugger.js (content/RemoteDebugger.js)
#ifdef MOZ_SERVICES_HEALTHREPORT

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