diff --git a/dom/activities/tests/mochi/mochitest.ini b/dom/activities/tests/mochi/mochitest.ini
index 23925f10b9..00bdf46069 100644
--- a/dom/activities/tests/mochi/mochitest.ini
+++ b/dom/activities/tests/mochi/mochitest.ini
@@ -1,5 +1,5 @@
[DEFAULT]
-skip-if = e10s
+skip-if = (buildapp != 'b2g' && buildapp != 'mulet')
support-files =
system.webapp
system.webapp^headers^
diff --git a/dom/apps/InterAppCommService.jsm b/dom/apps/InterAppCommService.jsm
index 7a9dc0e679..535069334f 100644
--- a/dom/apps/InterAppCommService.jsm
+++ b/dom/apps/InterAppCommService.jsm
@@ -883,6 +883,14 @@ this.InterAppCommService = {
if (DEBUG) {
debug("Unregistering message port for " + manifestURL);
}
+
+ let receiver = identity.isPublisher ? identity.pair.subscriber
+ : identity.pair.publisher;
+ receiver.target.sendAsyncMessage("InterAppMessagePort:OnClose",
+ { manifestURL: receiver.manifestURL,
+ pageURL: receiver.pageURL,
+ messagePortID: messagePortID });
+
delete this._messagePortPairs[messagePortID];
},
@@ -901,7 +909,7 @@ this.InterAppCommService = {
messagePortIDs.push(messagePortID);
// Send a shutdown message to the part of the pair that is still alive.
let actor = pair.publisher.target === aTarget ? pair.subscriber
- : pair.publisher;
+ : pair.publisher;
actor.target.sendAsyncMessage("InterAppMessagePort:Shutdown",
{ manifestURL: actor.manifestURL,
pageURL: actor.pageURL,
diff --git a/dom/apps/InterAppMessagePort.js b/dom/apps/InterAppMessagePort.js
index 7d3ec9ba7a..4a9b3a9794 100644
--- a/dom/apps/InterAppMessagePort.js
+++ b/dom/apps/InterAppMessagePort.js
@@ -30,7 +30,8 @@ XPCOMUtils.defineLazyServiceGetter(this, "appsService",
"@mozilla.org/AppsService;1",
"nsIAppsService");
-const kMessages = ["InterAppMessagePort:OnMessage",
+const kMessages = ["InterAppMessagePort:OnClose",
+ "InterAppMessagePort:OnMessage",
"InterAppMessagePort:Shutdown"];
function InterAppMessagePort() {
@@ -66,6 +67,7 @@ InterAppMessagePort.prototype = {
this._started = false;
this._closed = false;
this._messageQueue = [];
+ this._deferredClose = false;
},
// WebIDL implementation for constructor.
@@ -131,6 +133,10 @@ InterAppMessagePort.prototype = {
let message = this._messageQueue.shift();
this._dispatchMessage(message);
}
+
+ if (this._deferredClose) {
+ this._dispatchClose();
+ }
},
close: function() {
@@ -143,6 +149,7 @@ InterAppMessagePort.prototype = {
}
this._closed = true;
+ this._deferredClose = false;
this._messageQueue.length = 0;
// When this method called on a local port that is entangled with another
@@ -152,6 +159,8 @@ InterAppMessagePort.prototype = {
manifestURL: this._manifestURL });
this.removeMessageListeners(kMessages);
+
+ this._dispatchClose();
},
get onmessage() {
@@ -176,6 +185,16 @@ InterAppMessagePort.prototype = {
this.start();
},
+ get onclose() {
+ if (DEBUG) debug("Getting onclose handler.");
+ return this.__DOM_IMPL__.getEventHandler("onclose");
+ },
+
+ set onclose(aHandler) {
+ if (DEBUG) debug("Setting onclose handler.");
+ this.__DOM_IMPL__.setEventHandler("onclose", aHandler);
+ },
+
_dispatchMessage: function _dispatchMessage(aMessage) {
let wrappedMessage = Cu.cloneInto(aMessage, this._window);
if (DEBUG) {
@@ -189,6 +208,15 @@ InterAppMessagePort.prototype = {
this.__DOM_IMPL__.dispatchEvent(event);
},
+ _dispatchClose() {
+ if (DEBUG) debug("_dispatchClose");
+ let event = new this._window.Event("close", {
+ bubbles: true,
+ cancelable: true
+ });
+ this.__DOM_IMPL__.dispatchEvent(event);
+ },
+
receiveMessage: function(aMessage) {
if (DEBUG) debug("receiveMessage: name: " + aMessage.name);
@@ -217,11 +245,32 @@ InterAppMessagePort.prototype = {
this._dispatchMessage(message.message);
break;
+ case "InterAppMessagePort:OnClose":
+ if (this._closed) {
+ if (DEBUG) debug("close() has been called. Drop the message.");
+ return;
+ }
+
+ // It is possible that one side of the port posts messages and calls
+ // close() before calling start() or setting the onmessage handler. In
+ // that case we need to queue the messages and defer the onclose event
+ // until the messages are delivered to the other side of the port.
+ if (!this._started) {
+ if (DEBUG) debug("Not yet called start(). Defer close notification.");
+ this._deferredClose = true;
+ return;
+ }
+
+ this._dispatchClose();
+ break;
+
case "InterAppMessagePort:Shutdown":
this.close();
break;
+
default:
- if (DEBUG) debug("Error! Shouldn't fall into this case.");
+ dump("WARNING - Invalid InterAppMessagePort message type " +
+ aMessage.name + "\n");
break;
}
}
diff --git a/dom/apps/moz.build b/dom/apps/moz.build
index 419ad9a45f..866dc47222 100644
--- a/dom/apps/moz.build
+++ b/dom/apps/moz.build
@@ -8,7 +8,10 @@ XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
MOCHITEST_MANIFESTS += ['tests/mochitest.ini']
-MOCHITEST_CHROME_MANIFESTS += ['tests/chrome.ini']
+MOCHITEST_CHROME_MANIFESTS += [
+ 'tests/b2g_chrome.ini',
+ 'tests/chrome.ini'
+]
EXPORTS.mozilla.dom += [
'InterAppComm.h',
diff --git a/dom/apps/tests/b2g_chrome.ini b/dom/apps/tests/b2g_chrome.ini
new file mode 100644
index 0000000000..bc13bf326b
--- /dev/null
+++ b/dom/apps/tests/b2g_chrome.ini
@@ -0,0 +1,6 @@
+[DEFAULT]
+skip-if = buildapp != 'b2g'
+support-files =
+ iac/*
+
+[test_iac.html]
diff --git a/dom/apps/tests/chrome.ini b/dom/apps/tests/chrome.ini
index 3348cb6db4..e908d99539 100644
--- a/dom/apps/tests/chrome.ini
+++ b/dom/apps/tests/chrome.ini
@@ -1,5 +1,5 @@
[DEFAULT]
-skip-if = buildapp == 'b2g' || os == 'android'
+skip-if = buildapp != 'mulet'
support-files =
asmjs/*
common.js
diff --git a/dom/apps/tests/file_hosted_certified.webapp b/dom/apps/tests/file_hosted_certified.webapp
index c027b37efb..d1b940f889 100644
--- a/dom/apps/tests/file_hosted_certified.webapp
+++ b/dom/apps/tests/file_hosted_certified.webapp
@@ -1,6 +1,6 @@
{
"name": "Certified hosted app",
- "description": "An app that can't only be installed in dev mode.",
+ "description": "An app that can only be installed in dev mode.",
"launch_path": "/tests/dom/apps/tests/file_app.sjs?apptype=hosted",
"type": "certified"
}
diff --git a/dom/apps/tests/iac/README.txt b/dom/apps/tests/iac/README.txt
new file mode 100644
index 0000000000..326536bf28
--- /dev/null
+++ b/dom/apps/tests/iac/README.txt
@@ -0,0 +1,3 @@
+subscriber.list and publisher.zip contain the lists of files that are part of each app.
+
+To update the packages of both apps when changing one of those files listed on *.list, run makezips.sh.
diff --git a/dom/apps/tests/iac/makezips.sh b/dom/apps/tests/iac/makezips.sh
new file mode 100644
index 0000000000..f94d4a9e01
--- /dev/null
+++ b/dom/apps/tests/iac/makezips.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+rm publisher/publisher.zip
+rm subscriber/subscriber.zip
+cd publisher
+zip publisher.zip `cat publisher.list`
+cd ../subscriber
+zip subscriber.zip `cat subscriber.list`
+cd ..
diff --git a/dom/apps/tests/iac/publisher/index.html b/dom/apps/tests/iac/publisher/index.html
new file mode 100644
index 0000000000..c584807b26
--- /dev/null
+++ b/dom/apps/tests/iac/publisher/index.html
@@ -0,0 +1,9 @@
+
+
+
+ Publisher app for IAC API
+
+
+
+
+
diff --git a/dom/apps/tests/iac/publisher/manifest.webapp b/dom/apps/tests/iac/publisher/manifest.webapp
new file mode 100644
index 0000000000..cc9343f220
--- /dev/null
+++ b/dom/apps/tests/iac/publisher/manifest.webapp
@@ -0,0 +1,5 @@
+{
+ "name": "IAC publisher app",
+ "launch_path": "/index.html",
+ "type": "certified"
+}
diff --git a/dom/apps/tests/iac/publisher/publisher.list b/dom/apps/tests/iac/publisher/publisher.list
new file mode 100644
index 0000000000..d94aad31cc
--- /dev/null
+++ b/dom/apps/tests/iac/publisher/publisher.list
@@ -0,0 +1,3 @@
+manifest.webapp
+index.html
+test.js
diff --git a/dom/apps/tests/iac/publisher/publisher.zip b/dom/apps/tests/iac/publisher/publisher.zip
new file mode 100644
index 0000000000..dcfc3cdf7f
Binary files /dev/null and b/dom/apps/tests/iac/publisher/publisher.zip differ
diff --git a/dom/apps/tests/iac/publisher/test.js b/dom/apps/tests/iac/publisher/test.js
new file mode 100644
index 0000000000..ea52bfc357
--- /dev/null
+++ b/dom/apps/tests/iac/publisher/test.js
@@ -0,0 +1,46 @@
+function ok(aCondition, aMessage) {
+ if (aCondition) {
+ alert("OK: " + aMessage);
+ } else {
+ alert("KO: " + aMessage);
+ }
+}
+
+function ready() {
+ alert("READY");
+}
+
+let _port = null;
+let responseReceived = false;
+
+function onmessage(message) {
+ responseReceived = (message.data == "response");
+ ok(responseReceived, "response received");
+}
+
+function onclose() {
+ ok(true, "onclose received");
+ if (responseReceived) {
+ ready();
+ }
+}
+
+(function makeConnection() {
+ ok(true, "Connecting");
+ navigator.mozApps.getSelf().onsuccess = event => {
+ ok(true, "Got self");
+ let app = event.target.result;
+ app.connect("a-connection").then(ports => {
+ if (!ports || !ports.length) {
+ return ok(false, "No ports");
+ }
+ ok(true, "Got port");
+ _port = ports[0];
+ _port.onmessage = onmessage;
+ _port.onclose = onclose;
+ _port.postMessage('something');
+ }).catch(error => {
+ ok(false, "Unexpected " + error);
+ });
+ };
+})();
diff --git a/dom/apps/tests/iac/publisher/update.webapp b/dom/apps/tests/iac/publisher/update.webapp
new file mode 100644
index 0000000000..10d4776faa
--- /dev/null
+++ b/dom/apps/tests/iac/publisher/update.webapp
@@ -0,0 +1,6 @@
+{
+ "name": "IAC publisher app",
+ "launch_path": "/index.html",
+ "package_path": "publisher.zip",
+ "type": "certified"
+}
diff --git a/dom/apps/tests/iac/publisher/update.webapp^headers^ b/dom/apps/tests/iac/publisher/update.webapp^headers^
new file mode 100644
index 0000000000..a2367b11c7
--- /dev/null
+++ b/dom/apps/tests/iac/publisher/update.webapp^headers^
@@ -0,0 +1 @@
+Content-Type: application/x-web-app-manifest+json
diff --git a/dom/apps/tests/iac/subscriber/index.html b/dom/apps/tests/iac/subscriber/index.html
new file mode 100644
index 0000000000..dcc352e18b
--- /dev/null
+++ b/dom/apps/tests/iac/subscriber/index.html
@@ -0,0 +1,9 @@
+
+
+
+ Subscriber app for IAC API
+
+
+
+
+
diff --git a/dom/apps/tests/iac/subscriber/manifest.webapp b/dom/apps/tests/iac/subscriber/manifest.webapp
new file mode 100644
index 0000000000..cd277b6496
--- /dev/null
+++ b/dom/apps/tests/iac/subscriber/manifest.webapp
@@ -0,0 +1,11 @@
+{
+ "name": "IAC subscriber app",
+ "launch_path": "/index.html",
+ "type": "certified",
+ "connections": {
+ "a-connection": {
+ "description": "A connection",
+ "rules": {}
+ }
+ }
+}
diff --git a/dom/apps/tests/iac/subscriber/subscriber.list b/dom/apps/tests/iac/subscriber/subscriber.list
new file mode 100644
index 0000000000..d94aad31cc
--- /dev/null
+++ b/dom/apps/tests/iac/subscriber/subscriber.list
@@ -0,0 +1,3 @@
+manifest.webapp
+index.html
+test.js
diff --git a/dom/apps/tests/iac/subscriber/subscriber.zip b/dom/apps/tests/iac/subscriber/subscriber.zip
new file mode 100644
index 0000000000..024252362a
Binary files /dev/null and b/dom/apps/tests/iac/subscriber/subscriber.zip differ
diff --git a/dom/apps/tests/iac/subscriber/test.js b/dom/apps/tests/iac/subscriber/test.js
new file mode 100644
index 0000000000..5cf5812f3e
--- /dev/null
+++ b/dom/apps/tests/iac/subscriber/test.js
@@ -0,0 +1,9 @@
+let port;
+navigator.mozSetMessageHandler('connection', request => {
+ port = request.port;
+ port.onmessage = () => {
+ port.postMessage('response');
+ port.close();
+ };
+});
+alert('READY');
diff --git a/dom/apps/tests/iac/subscriber/update.webapp b/dom/apps/tests/iac/subscriber/update.webapp
new file mode 100644
index 0000000000..a5833cd421
--- /dev/null
+++ b/dom/apps/tests/iac/subscriber/update.webapp
@@ -0,0 +1,12 @@
+{
+ "name": "IAC subscriber app",
+ "launch_path": "/index.html",
+ "type": "certified",
+ "package_path": "subscriber.zip",
+ "connections": {
+ "a-connection": {
+ "description": "A connection",
+ "rules": {}
+ }
+ }
+}
diff --git a/dom/apps/tests/iac/subscriber/update.webapp^headers^ b/dom/apps/tests/iac/subscriber/update.webapp^headers^
new file mode 100644
index 0000000000..a2367b11c7
--- /dev/null
+++ b/dom/apps/tests/iac/subscriber/update.webapp^headers^
@@ -0,0 +1 @@
+Content-Type: application/x-web-app-manifest+json
diff --git a/dom/apps/tests/mochitest.ini b/dom/apps/tests/mochitest.ini
index 8828904211..ae9fdf4364 100644
--- a/dom/apps/tests/mochitest.ini
+++ b/dom/apps/tests/mochitest.ini
@@ -1,5 +1,5 @@
[DEFAULT]
-skip-if = e10s
+skip-if = buildapp != 'b2g' && buildapp != 'mulet'
support-files =
addons/application.zip
addons/update.webapp
@@ -42,7 +42,8 @@ skip-if = os == "android" || toolkit == "gonk" # embed-apps doesn't work in moch
skip-if = os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
[test_bug_795164.html]
[test_bug_1168300.html]
-skip-if = toolkit == "gonk" # see bug 1175784
+skip-if = toolkit == "gonk" || e10s # see bug 1175784
+[test_checkInstalled.html]
[test_import_export.html]
[test_install_dev_mode.html]
[test_install_multiple_apps_origin.html]
diff --git a/dom/apps/tests/test_iac.html b/dom/apps/tests/test_iac.html
new file mode 100644
index 0000000000..45d02d2e22
--- /dev/null
+++ b/dom/apps/tests/test_iac.html
@@ -0,0 +1,237 @@
+
+
+
+
+ Test for IAC API
+
+
+
+
+
+
+
+Mozilla Bug {915880}
+
+
+
+
+
+
+
+
+
+
diff --git a/dom/apps/tests/test_packaged_app_install.html b/dom/apps/tests/test_packaged_app_install.html
index f03830a955..09ca0dbe16 100644
--- a/dom/apps/tests/test_packaged_app_install.html
+++ b/dom/apps/tests/test_packaged_app_install.html
@@ -155,7 +155,7 @@ var steps = [
PackagedTestHelper.gAppName);
},
function() {
- PackagedTestHelper.setAppVersion(1, PackagedTestHelper.next);
+ PackagedTestHelper.setAppVersion(1, PackagedTestHelper.next);
},
function() {
// Test mini-manifest app name is different from the webapp manifest name.
diff --git a/dom/base/test/test_navigator_resolve_identity.html b/dom/base/test/test_navigator_resolve_identity.html
index 3bfeaf1ce2..882853525a 100644
--- a/dom/base/test/test_navigator_resolve_identity.html
+++ b/dom/base/test/test_navigator_resolve_identity.html
@@ -19,13 +19,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=985827
var y = navigator.mozContacts;
is(x, y, "Should have gotten the same mozContacts object again");
- // Test Javascript-navigator-property objects
- x = navigator.mozApps;
- is(typeof x, "object", "Should have a mozApps object");
- delete navigator.mozApps;
- y = navigator.mozApps;
- is(x, y, "Should have gotten the same mozApps object again");
-
diff --git a/dom/base/test/test_navigator_resolve_identity_xrays.xul b/dom/base/test/test_navigator_resolve_identity_xrays.xul
index d2b733ac30..41ff4591b4 100644
--- a/dom/base/test/test_navigator_resolve_identity_xrays.xul
+++ b/dom/base/test/test_navigator_resolve_identity_xrays.xul
@@ -32,11 +32,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=985827
is(nav.mozContacts, nav.mozContacts,
"Should have gotten the same mozContacts object again");
- // Test Javascript-navigator-property objects
- is(typeof nav.mozApps, "object", "Should have a mozApps object");
- is(nav.mozApps, nav.mozApps,
- "Should have gotten the same mozApps object again");
-
SimpleTest.finish();
});
]]>
diff --git a/dom/bindings/test/test_bug707564-chrome.html b/dom/bindings/test/test_bug707564-chrome.html
index cf5f8d78ff..7e3185a2a9 100644
--- a/dom/bindings/test/test_bug707564-chrome.html
+++ b/dom/bindings/test/test_bug707564-chrome.html
@@ -26,19 +26,19 @@ function test()
is(nav.foopy, undefined, "We should have an Xray now");
is(nav.wrappedJSObject.foopy, 5, "We should have the right navigator object");
var props = Object.getOwnPropertyNames(nav);
- isnot(props.indexOf("mozApps"), -1,
- "Should enumerate a mozApps property on navigator xray");
+ isnot(props.indexOf("mozContacts"), -1,
+ "Should enumerate a mozContacts property on navigator xray");
var nav = document.getElementById("t2").contentWindow.navigator;
is(nav.foopy, undefined, "We should have an Xray now again");
is(nav.wrappedJSObject.foopy, 5, "We should have the right navigator object again");
var found = false;
for (var name in nav) {
- if (name == "mozApps") {
+ if (name == "mozContacts") {
found = true;
}
}
- ok(found, "Should enumerate a mozApps property on navigator xray via for...in");
+ ok(found, "Should enumerate a mozContacts property on navigator xray via for...in");
SimpleTest.finish();
}
diff --git a/dom/bindings/test/test_bug707564.html b/dom/bindings/test/test_bug707564.html
index 8b0f9068b0..fb0929c633 100644
--- a/dom/bindings/test/test_bug707564.html
+++ b/dom/bindings/test/test_bug707564.html
@@ -15,17 +15,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=707564
addLoadEvent(function() {
var props = Object.getOwnPropertyNames(frames[0].navigator);
- isnot(props.indexOf("mozApps"), -1,
- "Should enumerate a mozApps property on navigator");
+ isnot(props.indexOf("mozContacts"), -1,
+ "Should enumerate a mozContacts property on navigator");
// Now enumerate a different navigator object
var found = false;
for (var name in frames[1].navigator) {
- if (name == "mozApps") {
+ if (name == "mozContacts") {
found = true;
}
}
- ok(found, "Should enumerate a mozApps property on navigator via for...in");
+ ok(found, "Should enumerate a mozContacts property on navigator via for...in");
SimpleTest.finish();
});
diff --git a/dom/broadcastchannel/tests/mochitest.ini b/dom/broadcastchannel/tests/mochitest.ini
index f37dd65305..77419ee048 100644
--- a/dom/broadcastchannel/tests/mochitest.ini
+++ b/dom/broadcastchannel/tests/mochitest.ini
@@ -20,7 +20,7 @@ support-files =
[test_broadcastchannel_worker.html]
[test_broadcastchannel_worker_alive.html]
[test_broadcastchannel_mozbrowser.html]
-skip-if = e10s || buildapp == 'b2g'
+skip-if = buildapp != 'mulet'
[test_broadcastchannel_mozbrowser2.html]
-skip-if = e10s || buildapp == 'b2g'
+skip-if = buildapp != 'mulet'
[test_bfcache.html]
diff --git a/dom/browser-element/mochitest/chrome.ini b/dom/browser-element/mochitest/chrome.ini
index 15e694812b..e45dc2123b 100644
--- a/dom/browser-element/mochitest/chrome.ini
+++ b/dom/browser-element/mochitest/chrome.ini
@@ -1,5 +1,5 @@
[DEFAULT]
-skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
+skip-if = (buildapp != 'b2g' && buildapp != 'mulet') || (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
support-files =
browserElement_NotifyChannel.js
diff --git a/dom/browser-element/mochitest/mochitest-oop.ini b/dom/browser-element/mochitest/mochitest-oop.ini
index f4e239656e..e543bb5196 100644
--- a/dom/browser-element/mochitest/mochitest-oop.ini
+++ b/dom/browser-element/mochitest/mochitest-oop.ini
@@ -22,9 +22,9 @@ skip-if = toolkit=='gonk' || (toolkit == 'gonk' && !debug)
[test_browserElement_oop_Alert.html]
[test_browserElement_oop_AlertInFrame.html]
[test_browserElement_oop_AllowEmbedAppsInNestedOOIframe.html]
-skip-if = toolkit=='gonk'
+skip-if = toolkit == 'gonk' || buildapp != 'b2g'
[test_browserElement_oop_AppFramePermission.html]
-skip-if = (toolkit == 'gonk' && !debug)
+skip-if = (toolkit == 'gonk' && !debug) || buildapp != 'b2g'
[test_browserElement_oop_AppWindowNamespace.html]
skip-if = (toolkit == 'gonk' && !debug)
[test_browserElement_oop_Auth.html]
@@ -40,6 +40,7 @@ skip-if = (toolkit == 'gonk' && !debug)
[test_browserElement_oop_DOMRequestError.html]
[test_browserElement_oop_DataURI.html]
[test_browserElement_oop_DisallowEmbedAppsInOOP.html]
+skip-if = buildapp != 'b2g'
[test_browserElement_oop_DocumentFirstPaint.html]
[test_browserElement_oop_Download.html]
disabled = bug 1022281
diff --git a/dom/browser-element/mochitest/mochitest.ini b/dom/browser-element/mochitest/mochitest.ini
index 2dc9cb8096..a69c4907ab 100644
--- a/dom/browser-element/mochitest/mochitest.ini
+++ b/dom/browser-element/mochitest/mochitest.ini
@@ -1,5 +1,5 @@
[DEFAULT]
-skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || e10s
+skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || e10s
support-files =
../../../browser/base/content/test/general/audio.ogg
../../../dom/media/test/short-video.ogv
@@ -154,7 +154,7 @@ support-files =
skip-if = buildapp == 'b2g'
[test_browserElement_inproc_AlertInFrame.html]
[test_browserElement_inproc_AppFramePermission.html]
-skip-if = toolkit == 'android' || buildapp == 'b2g'
+skip-if = toolkit == 'android' || buildapp != 'mulet'
[test_browserElement_inproc_AppWindowNamespace.html]
skip-if = toolkit == 'android' || buildapp == 'b2g' # android(TIMED_OUT, bug 783509) androidx86(TIMED_OUT, bug 783509)
[test_browserElement_inproc_Auth.html]
@@ -175,7 +175,7 @@ skip-if = buildapp == 'b2g'
[test_browserElement_inproc_DOMRequestError.html]
[test_browserElement_inproc_DataURI.html]
[test_browserElement_inproc_DisallowEmbedAppsInOOP.html]
-skip-if = os == "android" || toolkit == 'gonk' # embed-apps doesn't work in the mochitest app
+skip-if = os == "android" || toolkit == 'gonk' || buildapp != 'mulet' # embed-apps doesn't work in the mochitest app
[test_browserElement_inproc_DocumentFirstPaint.html]
[test_browserElement_inproc_Download.html]
disabled = bug 1022281
@@ -213,7 +213,7 @@ skip-if = (toolkit == 'gonk' && !debug)
# Disabled on B2G Emulator because permission cannot be asserted in content process,
# need to fix either bug 1094055 or bug 1020135.
[test_browserElement_inproc_Proxy.html]
-skip-if = (toolkit == 'gonk')
+skip-if = toolkit == 'gonk' || buildapp == 'mulet'
[test_browserElement_inproc_PurgeHistory.html]
[test_browserElement_inproc_ReloadPostRequest.html]
[test_browserElement_inproc_RemoveBrowserElement.html]
diff --git a/dom/cache/test/mochitest/mochitest.ini b/dom/cache/test/mochitest/mochitest.ini
index 63fcf08bb3..8395eb9c0f 100644
--- a/dom/cache/test/mochitest/mochitest.ini
+++ b/dom/cache/test/mochitest/mochitest.ini
@@ -42,7 +42,7 @@ support-files =
[test_cache_restart.html]
[test_cache_shrink.html]
[test_cache_clear_on_app_uninstall.html]
- skip-if = e10s || buildapp == 'b2g' # bug 1178685
+ skip-if = buildapp != 'mulet' || e10s # bug 1178685
[test_cache_orphaned_cache.html]
[test_cache_orphaned_body.html]
[test_cache_untrusted.html]
diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp
index 979b202092..ddd0a0a712 100644
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -3488,13 +3488,9 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcess
virtual nscoord GetWidth()
{
- gfxTextRun::Metrics textRunMetrics = mTextRun->MeasureText(0,
- mTextRun->GetLength(),
- mDoMeasureBoundingBox ?
- gfxFont::TIGHT_INK_EXTENTS :
- gfxFont::LOOSE_INK_EXTENTS,
- mDrawTarget,
- nullptr);
+ gfxTextRun::Metrics textRunMetrics = mTextRun->MeasureText(
+ mDoMeasureBoundingBox ? gfxFont::TIGHT_INK_EXTENTS
+ : gfxFont::LOOSE_INK_EXTENTS, mDrawTarget);
// this only measures the height; the total width is gotten from the
// the return value of ProcessText.
@@ -3524,13 +3520,10 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcess
// glyph string on OS X and DWrite where textrun widths may
// involve fractional pixels.
gfxTextRun::Metrics textRunMetrics =
- mTextRun->MeasureText(0,
- mTextRun->GetLength(),
- mDoMeasureBoundingBox ?
- gfxFont::TIGHT_INK_EXTENTS :
- gfxFont::LOOSE_INK_EXTENTS,
- mDrawTarget,
- nullptr);
+ mTextRun->MeasureText(mDoMeasureBoundingBox ?
+ gfxFont::TIGHT_INK_EXTENTS :
+ gfxFont::LOOSE_INK_EXTENTS,
+ mDrawTarget);
inlineCoord += textRunMetrics.mAdvanceWidth;
// old code was:
// point.x += width * mAppUnitsPerDevPixel;
diff --git a/dom/datastore/tests/mochitest.ini b/dom/datastore/tests/mochitest.ini
index 4cba8f7ff7..fda1c4c0c8 100644
--- a/dom/datastore/tests/mochitest.ini
+++ b/dom/datastore/tests/mochitest.ini
@@ -1,5 +1,5 @@
[DEFAULT]
-skip-if = e10s
+skip-if = (buildapp != 'b2g' && buildapp != 'mulet')
support-files =
file_app_install.html
file_readonly.html
diff --git a/dom/events/ContentEventHandler.cpp b/dom/events/ContentEventHandler.cpp
index 586bced716..4ffc9aea73 100644
--- a/dom/events/ContentEventHandler.cpp
+++ b/dom/events/ContentEventHandler.cpp
@@ -658,10 +658,9 @@ ContentEventHandler::AppendFontRanges(FontRangeArray& aFontRanges,
}
}
- uint32_t skipStart = iter.ConvertOriginalToSkipped(frameXPStart);
- uint32_t skipEnd = iter.ConvertOriginalToSkipped(frameXPEnd);
- gfxTextRun::GlyphRunIterator runIter(
- textRun, skipStart, skipEnd - skipStart);
+ gfxTextRun::Range skipRange(iter.ConvertOriginalToSkipped(frameXPStart),
+ iter.ConvertOriginalToSkipped(frameXPEnd));
+ gfxTextRun::GlyphRunIterator runIter(textRun, skipRange);
int32_t lastXPEndOffset = frameXPStart;
while (runIter.NextRun()) {
gfxFont* font = runIter.GetGlyphRun()->mFont.get();
diff --git a/dom/events/test/test_all_synthetic_events.html b/dom/events/test/test_all_synthetic_events.html
index 50d15c4311..c7ca5f9a82 100644
--- a/dom/events/test/test_all_synthetic_events.html
+++ b/dom/events/test/test_all_synthetic_events.html
@@ -489,7 +489,14 @@ const kEventConstructors = {
return new SpeechRecognitionEvent(aName, aProps);
},
},
+ SpeechSynthesisErrorEvent: { create: function (aName, aProps) {
+ aProps.error = "synthesis-unavailable";
+ aProps.utterance = new SpeechSynthesisUtterance("Hello World");
+ return new SpeechSynthesisErrorEvent(aName, aProps);
+ },
+ },
SpeechSynthesisEvent: { create: function (aName, aProps) {
+ aProps.utterance = new SpeechSynthesisUtterance("Hello World");
return new SpeechSynthesisEvent(aName, aProps);
},
},
diff --git a/dom/indexedDB/test/mochitest.ini b/dom/indexedDB/test/mochitest.ini
index 20a0ebbb05..1c3811e8f3 100644
--- a/dom/indexedDB/test/mochitest.ini
+++ b/dom/indexedDB/test/mochitest.ini
@@ -114,10 +114,10 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_app_isolation_inproc.html]
# The app isolation tests are only supposed to run in the main process.
-skip-if = buildapp == 'b2g' || buildapp == 'mulet' || e10s
+skip-if = buildapp == 'b2g' || e10s
[test_app_isolation_oop.html]
# The app isolation tests are only supposed to run in the main process.
-skip-if = buildapp == 'b2g' || buildapp == 'mulet' || e10s
+skip-if = buildapp == 'b2g' || e10s
[test_autoIncrement.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_autoIncrement_indexes.html]
@@ -134,13 +134,13 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_blob_worker_crash.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_blob_worker_xhr_post.html]
-skip-if = ((buildapp == 'b2g' && toolkit != 'gonk') || (e10s && toolkit == 'windows')) # Bug 931116
+skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_blob_worker_xhr_post_multifile.html]
-skip-if = ((buildapp == 'b2g' && toolkit != 'gonk') || (e10s && toolkit == 'windows')) # Bug 931116
+skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_blob_worker_xhr_read.html]
-skip-if = ((buildapp == 'b2g' && toolkit != 'gonk') || (e10s && toolkit == 'windows')) # Bug 931116
+skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_blob_worker_xhr_read_slice.html]
-skip-if = ((buildapp == 'b2g' && toolkit != 'gonk') || (e10s && toolkit == 'windows')) # Bug 931116
+skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_blocked_order.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_bug937006.html]
@@ -361,14 +361,14 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_webapp_clearBrowserData_inproc_inproc.html]
# The clearBrowserData tests are only supposed to run in the main process.
# They currently time out on android.
-skip-if = buildapp == 'b2g' || buildapp == 'mulet' || e10s || toolkit == 'android'
+skip-if = buildapp != 'mulet'
[test_webapp_clearBrowserData_inproc_oop.html]
# The clearBrowserData tests are only supposed to run in the main process.
# They currently time out on android.
-skip-if = buildapp == 'b2g' || buildapp == 'mulet' || e10s || toolkit == 'android'
+skip-if = buildapp != 'mulet'
[test_webapp_clearBrowserData_oop_inproc.html]
# The clearBrowserData tests are only supposed to run in the main process.
# They currently time out on android.
-skip-if = buildapp == 'b2g' || buildapp == 'mulet' || e10s || toolkit == 'android'
+skip-if = buildapp != 'mulet'
[test_serviceworker.html]
skip-if = buildapp == 'b2g'
diff --git a/dom/media/test/crashtests/crashtests.list b/dom/media/test/crashtests/crashtests.list
index df560ab2a0..0047226338 100644
--- a/dom/media/test/crashtests/crashtests.list
+++ b/dom/media/test/crashtests/crashtests.list
@@ -78,7 +78,7 @@ load 1080986.html
load 1122218.html
load 1127188.html
load 1157994.html
-load 1158427.html
+skip-if(!B2G) load 1158427.html
load 1185176.html
load 1185192.html
load analyser-channels-1.html
diff --git a/dom/media/webspeech/synth/SpeechSynthesisUtterance.cpp b/dom/media/webspeech/synth/SpeechSynthesisUtterance.cpp
index b4886e918f..3cb9e1ba3a 100644
--- a/dom/media/webspeech/synth/SpeechSynthesisUtterance.cpp
+++ b/dom/media/webspeech/synth/SpeechSynthesisUtterance.cpp
@@ -162,6 +162,7 @@ SpeechSynthesisUtterance::DispatchSpeechSynthesisEvent(const nsAString& aEventTy
SpeechSynthesisEventInit init;
init.mBubbles = false;
init.mCancelable = false;
+ init.mUtterance = this;
init.mCharIndex = aCharIndex;
init.mElapsedTime = aElapsedTime;
init.mName = aName;
diff --git a/dom/media/webspeech/synth/test/file_setup.html b/dom/media/webspeech/synth/test/file_setup.html
index a48754c2fa..d851349525 100644
--- a/dom/media/webspeech/synth/test/file_setup.html
+++ b/dom/media/webspeech/synth/test/file_setup.html
@@ -27,6 +27,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=525444
ok(SpeechSynthesis, "SpeechSynthesis exists in global scope");
ok(SpeechSynthesisVoice, "SpeechSynthesisVoice exists in global scope");
+ok(SpeechSynthesisErrorEvent, "SpeechSynthesisErrorEvent exists in global scope");
ok(SpeechSynthesisEvent, "SpeechSynthesisEvent exists in global scope");
// SpeechSynthesisUtterance is the only type that has a constructor
diff --git a/dom/messages/test/chrome.ini b/dom/messages/test/chrome.ini
index cf8cbd4ad9..bdcc745bd5 100644
--- a/dom/messages/test/chrome.ini
+++ b/dom/messages/test/chrome.ini
@@ -1,5 +1,5 @@
[DEFAULT]
-skip-if = (buildapp != "browser") || e10s
+skip-if = e10s
support-files =
file_hasPendingMessage.html
invalid_manifest.webapp
@@ -8,4 +8,6 @@ support-files =
manifest.webapp^headers^
[test_hasPendingMessage.html]
+skip-if = buildapp != "browser"
[test_sysmsg_registration.html]
+skip-if = buildapp != 'mulet'
diff --git a/dom/mobileconnection/tests/marionette/test_mobile_preferred_network_type.js b/dom/mobileconnection/tests/marionette/test_mobile_preferred_network_type.js
index c1b26bded0..1bb31a6a48 100644
--- a/dom/mobileconnection/tests/marionette/test_mobile_preferred_network_type.js
+++ b/dom/mobileconnection/tests/marionette/test_mobile_preferred_network_type.js
@@ -37,6 +37,9 @@ const TEST_DATA = [
}, {
preferredNetworkType: "lte",
expectedErrorMessage: "ModeNotSupported"
+ }, {
+ preferredNetworkType: "lte/wcdma",
+ expectedErrorMessage: "ModeNotSupported"
},
// Test passing an invalid mode. We expect to get an exception here.
{
diff --git a/dom/network/NetworkStatsManager.js b/dom/network/NetworkStatsManager.js
index 83644fc32d..1c3d5e3791 100644
--- a/dom/network/NetworkStatsManager.js
+++ b/dom/network/NetworkStatsManager.js
@@ -111,7 +111,6 @@ NetworkStatsAlarm.prototype = {
const NETWORKSTATSMANAGER_CONTRACTID = "@mozilla.org/networkStatsManager;1";
const NETWORKSTATSMANAGER_CID = Components.ID("{ceb874cd-cc1a-4e65-b404-cc2d3e42425f}");
-const nsIDOMMozNetworkStatsManager = Ci.nsIDOMMozNetworkStatsManager;
function NetworkStatsManager() {
if (DEBUG) {
@@ -122,40 +121,25 @@ function NetworkStatsManager() {
NetworkStatsManager.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
- checkPrivileges: function checkPrivileges() {
- if (!this.hasPrivileges) {
- throw Components.Exception("Permission denied", Cr.NS_ERROR_FAILURE);
- }
- },
-
getSamples: function getSamples(aNetwork, aStart, aEnd, aOptions) {
- this.checkPrivileges();
-
- if (aStart.constructor.name !== "Date" ||
- aEnd.constructor.name !== "Date" ||
- !(aNetwork instanceof this.window.MozNetworkStatsInterface) ||
- aStart > aEnd) {
+ if (aStart > aEnd) {
throw Components.results.NS_ERROR_INVALID_ARG;
}
- let appManifestURL = null;
- let browsingTrafficOnly = false;
- let serviceType = null;
- if (aOptions) {
- // appManifestURL is used to query network statistics by app;
- // serviceType is used to query network statistics by system service.
- // It is illegal to specify both of them at the same time.
- if (aOptions.appManifestURL && aOptions.serviceType) {
- throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
- }
- // browsingTrafficOnly is meaningful only when querying by app.
- if (!aOptions.appManifestURL && aOptions.browsingTrafficOnly) {
- throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
- }
- appManifestURL = aOptions.appManifestURL;
- serviceType = aOptions.serviceType;
- browsingTrafficOnly = aOptions.browsingTrafficOnly || false;
+ // appManifestURL is used to query network statistics by app;
+ // serviceType is used to query network statistics by system service.
+ // It is illegal to specify both of them at the same time.
+ if (aOptions.appManifestURL && aOptions.serviceType) {
+ throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
}
+ // browsingTrafficOnly is meaningful only when querying by app.
+ if (!aOptions.appManifestURL && aOptions.browsingTrafficOnly) {
+ throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
+ }
+
+ let appManifestURL = aOptions.appManifestURL;
+ let serviceType = aOptions.serviceType;
+ let browsingTrafficOnly = aOptions.browsingTrafficOnly;
// TODO Bug 929410 Date object cannot correctly pass through cpmm/ppmm IPC
// This is just a work-around by passing timestamp numbers.
@@ -175,12 +159,6 @@ NetworkStatsManager.prototype = {
},
clearStats: function clearStats(aNetwork) {
- this.checkPrivileges();
-
- if (!aNetwork instanceof this.window.MozNetworkStatsInterface) {
- throw Components.results.NS_ERROR_INVALID_ARG;
- }
-
let request = this.createRequest();
cpmm.sendAsyncMessage("NetworkStats:Clear",
{ network: aNetwork.toJSON(),
@@ -189,8 +167,6 @@ NetworkStatsManager.prototype = {
},
clearAllStats: function clearAllStats() {
- this.checkPrivileges();
-
let request = this.createRequest();
cpmm.sendAsyncMessage("NetworkStats:ClearAll",
{id: this.getRequestId(request)});
@@ -198,17 +174,6 @@ NetworkStatsManager.prototype = {
},
addAlarm: function addAlarm(aNetwork, aThreshold, aOptions) {
- this.checkPrivileges();
-
- if (!aOptions) {
- aOptions = Object.create(null);
- }
-
- if (aOptions.startTime && aOptions.startTime.constructor.name !== "Date" ||
- !(aNetwork instanceof this.window.MozNetworkStatsInterface)) {
- throw Components.results.NS_ERROR_INVALID_ARG;
- }
-
let request = this.createRequest();
cpmm.sendAsyncMessage("NetworkStats:SetAlarm",
{id: this.getRequestId(request),
@@ -222,13 +187,8 @@ NetworkStatsManager.prototype = {
},
getAllAlarms: function getAllAlarms(aNetwork) {
- this.checkPrivileges();
-
let network = null;
if (aNetwork) {
- if (!aNetwork instanceof this.window.MozNetworkStatsInterface) {
- throw Components.results.NS_ERROR_INVALID_ARG;
- }
network = aNetwork.toJSON();
}
@@ -241,8 +201,6 @@ NetworkStatsManager.prototype = {
},
removeAlarms: function removeAlarms(aAlarmId) {
- this.checkPrivileges();
-
if (aAlarmId == 0) {
aAlarmId = -1;
}
@@ -257,8 +215,6 @@ NetworkStatsManager.prototype = {
},
getAvailableNetworks: function getAvailableNetworks() {
- this.checkPrivileges();
-
let request = this.createRequest();
cpmm.sendAsyncMessage("NetworkStats:GetAvailableNetworks",
{ id: this.getRequestId(request) });
@@ -266,8 +222,6 @@ NetworkStatsManager.prototype = {
},
getAvailableServiceTypes: function getAvailableServiceTypes() {
- this.checkPrivileges();
-
let request = this.createRequest();
cpmm.sendAsyncMessage("NetworkStats:GetAvailableServiceTypes",
{ id: this.getRequestId(request) });
@@ -275,12 +229,10 @@ NetworkStatsManager.prototype = {
},
get sampleRate() {
- this.checkPrivileges();
return cpmm.sendSyncMessage("NetworkStats:SampleRate")[0];
},
get maxStorageAge() {
- this.checkPrivileges();
return cpmm.sendSyncMessage("NetworkStats:MaxStorageAge")[0];
},
@@ -390,27 +342,7 @@ NetworkStatsManager.prototype = {
},
init: function(aWindow) {
- // Set navigator.mozNetworkStats to null.
- if (!Services.prefs.getBoolPref("dom.mozNetworkStats.enabled")) {
- return null;
- }
-
let principal = aWindow.document.nodePrincipal;
- let secMan = Services.scriptSecurityManager;
- let perm = principal == secMan.getSystemPrincipal() ?
- Ci.nsIPermissionManager.ALLOW_ACTION :
- Services.perms.testExactPermissionFromPrincipal(principal,
- "networkstats-manage");
-
- // Only pages with perm set can use the netstats.
- this.hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION;
- if (DEBUG) {
- debug("has privileges: " + this.hasPrivileges);
- }
-
- if (!this.hasPrivileges) {
- return null;
- }
this.initDOMRequestHelper(aWindow, ["NetworkStats:Get:Return",
"NetworkStats:GetAvailableNetworks:Return",
@@ -443,16 +375,10 @@ NetworkStatsManager.prototype = {
},
classID : NETWORKSTATSMANAGER_CID,
- QueryInterface : XPCOMUtils.generateQI([nsIDOMMozNetworkStatsManager,
- Ci.nsIDOMGlobalPropertyInitializer,
- Ci.nsISupportsWeakReference,
- Ci.nsIObserver]),
-
- classInfo : XPCOMUtils.generateCI({classID: NETWORKSTATSMANAGER_CID,
- contractID: NETWORKSTATSMANAGER_CONTRACTID,
- classDescription: "NetworkStatsManager",
- interfaces: [nsIDOMMozNetworkStatsManager],
- flags: nsIClassInfo.DOM_OBJECT})
+ contractID : NETWORKSTATSMANAGER_CONTRACTID,
+ QueryInterface : XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
+ Ci.nsISupportsWeakReference,
+ Ci.nsIObserver]),
}
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkStatsAlarm,
diff --git a/dom/network/NetworkStatsManager.manifest b/dom/network/NetworkStatsManager.manifest
index 6231285731..8e8700910f 100644
--- a/dom/network/NetworkStatsManager.manifest
+++ b/dom/network/NetworkStatsManager.manifest
@@ -12,4 +12,3 @@ contract @mozilla.org/networkstatsalarm;1 {a93ea13e-409c-4189-9b1e-95fff220be55}
component {ceb874cd-cc1a-4e65-b404-cc2d3e42425f} NetworkStatsManager.js
contract @mozilla.org/networkStatsManager;1 {ceb874cd-cc1a-4e65-b404-cc2d3e42425f}
-category JavaScript-navigator-property mozNetworkStats @mozilla.org/networkStatsManager;1
diff --git a/dom/network/interfaces/moz.build b/dom/network/interfaces/moz.build
index 4b23638405..e2aef2cb12 100644
--- a/dom/network/interfaces/moz.build
+++ b/dom/network/interfaces/moz.build
@@ -12,7 +12,6 @@ XPIDL_SOURCES += [
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
XPIDL_SOURCES += [
- 'nsIDOMNetworkStatsManager.idl',
'nsIEthernetManager.idl',
'nsINetworkStatsServiceProxy.idl',
]
diff --git a/dom/network/tests/test_networkstats_alarms.html b/dom/network/tests/test_networkstats_alarms.html
index 5fcaef568e..b02879738e 100644
--- a/dom/network/tests/test_networkstats_alarms.html
+++ b/dom/network/tests/test_networkstats_alarms.html
@@ -48,32 +48,30 @@ var steps = [
};
req.onerror = function () {
- ok(req.error.name == "InvalidInterface", "Get InvalidInterface error");
+ is(req.error.name, "InvalidInterface", "Get InvalidInterface error");
next();
}
},
function () {
ok(true, "Calling addAlarm() with invalid network or parameters.");
+ var msg = "TypeError: Not enough arguments to MozNetworkStatsManager.addAlarm.";
try {
navigator.mozNetworkStats.addAlarm();
} catch(ex) {
- ok(ex.result == SpecialPowers.Cr.NS_ERROR_XPC_NOT_ENOUGH_ARGS,
- "addAlarm() throws NS_ERROR_XPC_NOT_ENOUGH_ARGS exception when no parameters");
+ is(ex.toString(), msg, "addAlarm() throws \"" + msg + "\" when no parameters");
}
try {
navigator.mozNetworkStats.addAlarm(100000);
} catch(ex) {
- ok(ex.result == SpecialPowers.Cr.NS_ERROR_XPC_NOT_ENOUGH_ARGS,
- "addAlarm() throws NS_ERROR_XPC_NOT_ENOUGH_ARGS exception when no network");
+ is(ex.toString(), msg, "addAlarm() throws " + msg + " when no network");
}
try {
navigator.mozNetworkStats.addAlarm(new window.MozNetworkStatsInterface(wifi));
} catch(ex) {
- ok(ex.result == SpecialPowers.Cr.NS_ERROR_XPC_NOT_ENOUGH_ARGS,
- "addAlarm() throws NS_ERROR_XPC_NOT_ENOUGH_ARGS exception when no threshold");
+ is(ex.toString(), msg, "addAlarm() throws " + msg + " when no threshold");
}
req = navigator.mozNetworkStats
@@ -84,7 +82,7 @@ var steps = [
};
req.onerror = function () {
- ok(req.error.name == "InvalidThresholdValue", "Get InvalidThresholdValue error");
+ is(req.error.name, "InvalidThresholdValue", "Get InvalidThresholdValue error");
next();
}
},
@@ -109,8 +107,8 @@ var steps = [
.getAllAlarms(new window.MozNetworkStatsInterface(wifi));
req.onsuccess = function () {
- ok(req.result.length == 1, "Only one alarm");
- ok(req.result[0].alarmId == 1, "Get correct alarmId");
+ is(req.result.length, 1, "Only one alarm");
+ is(req.result[0].alarmId, 1, "Get correct alarmId");
next();
};
@@ -226,8 +224,8 @@ SpecialPowers.pushPrefEnv({'set': [["dom.mozNetworkStats.enabled", true]]},
ok('mozNetworkStats' in navigator, "navigator.mozNetworkStats should exist");
- ok(navigator.mozNetworkStats instanceof SpecialPowers.Ci.nsIDOMMozNetworkStatsManager,
- "navigator.mozNetworkStats should be a nsIDOMMozNetworkStatsManager object");
+ ok(navigator.mozNetworkStats instanceof MozNetworkStatsManager,
+ "navigator.mozNetworkStats should be a MozNetworkStatsManager object");
test();
});
diff --git a/dom/network/tests/test_networkstats_basics.html b/dom/network/tests/test_networkstats_basics.html
index 2f6df9bc97..df6f49c9c1 100644
--- a/dom/network/tests/test_networkstats_basics.html
+++ b/dom/network/tests/test_networkstats_basics.html
@@ -333,8 +333,8 @@ SpecialPowers.pushPrefEnv({'set': [["dom.mozNetworkStats.enabled", true]]},
ok('mozNetworkStats' in navigator, "navigator.mozNetworkStats should exist");
- ok(navigator.mozNetworkStats instanceof SpecialPowers.Ci.nsIDOMMozNetworkStatsManager,
- "navigator.mozNetworkStats should be a nsIDOMMozNetworkStatsManager object");
+ ok(navigator.mozNetworkStats instanceof MozNetworkStatsManager,
+ "navigator.mozNetworkStats should be a MozNetworkStatsManager object");
test();
});
diff --git a/dom/network/tests/test_networkstats_disabled.html b/dom/network/tests/test_networkstats_disabled.html
index f515d778c6..59fe68f3b5 100644
--- a/dom/network/tests/test_networkstats_disabled.html
+++ b/dom/network/tests/test_networkstats_disabled.html
@@ -22,10 +22,8 @@ SpecialPowers.pushPrefEnv({'set': [["dom.mozNetworkStats.enabled", false]]},
ok(!SpecialPowers.getBoolPref("dom.mozNetworkStats.enabled"),
"Preference 'dom.mozNetworkStats.enabled' is false.");
- ok('mozNetworkStats' in navigator, "navigator.mozNetworkStats should exist");
-
- is(navigator.mozNetworkStats, null,
- "mozNetworkStats should be null when not enabled.");
+ ok(!('mozNetworkStats' in navigator),
+ "navigator.mozNetworkStats should not exist when pref not set");
SimpleTest.finish();
});
diff --git a/dom/network/tests/test_networkstats_enabled_no_perm.html b/dom/network/tests/test_networkstats_enabled_no_perm.html
index 93c3e3e4c8..1ec321acc0 100644
--- a/dom/network/tests/test_networkstats_enabled_no_perm.html
+++ b/dom/network/tests/test_networkstats_enabled_no_perm.html
@@ -27,25 +27,11 @@
ok(!SpecialPowers.hasPermission("networkstats-manage", document),
"Has no permission 'networkstats-manage'.");
- ok('mozNetworkStats' in navigator, "navigator.mozNetworkStats should exist");
+ ok(!('mozNetworkStats' in navigator),
+ "navigator.mozNetworkStats should not exist when permission not set");
- is(navigator.mozNetworkStats, null,
- "mozNetworkStats should be null when no permission.");
-
- var error;
- try {
- navigator.mozNetworkStats.getAvailableNetworks;
-
- ok(false,
- "Accessing navigator.mozNetworkStats.getAvailableNetworks should throw!");
- } catch (ex) {
- error = ex;
- }
-
- ok(error,
- "Got an exception accessing navigator.mozNetworkStats.getAvailableNetworks");
- SimpleTest.finish();
-}
+ SimpleTest.finish();
+ }
diff --git a/dom/network/tests/test_networkstats_enabled_perm.html b/dom/network/tests/test_networkstats_enabled_perm.html
index ceb32abe45..c22f8ecda6 100644
--- a/dom/network/tests/test_networkstats_enabled_perm.html
+++ b/dom/network/tests/test_networkstats_enabled_perm.html
@@ -30,8 +30,8 @@ SpecialPowers.pushPrefEnv({'set': [["dom.mozNetworkStats.enabled", true]]},
ok('mozNetworkStats' in navigator, "navigator.mozNetworkStats should exist");
- ok(navigator.mozNetworkStats instanceof SpecialPowers.Ci.nsIDOMMozNetworkStatsManager,
- "navigator.mozNetworkStats should be a nsIDOMMozNetworkStatsManager object");
+ ok(navigator.mozNetworkStats instanceof MozNetworkStatsManager,
+ "navigator.mozNetworkStats should be a MozNetworkStatsManager object");
SimpleTest.finish();
});
diff --git a/dom/network/tests/unit_stats/test_networkstats_db.js b/dom/network/tests/unit_stats/test_networkstats_db.js
index 15e5b2c36e..9e7778d2ac 100644
--- a/dom/network/tests/unit_stats/test_networkstats_db.js
+++ b/dom/network/tests/unit_stats/test_networkstats_db.js
@@ -41,8 +41,8 @@ function filterTimestamp(date) {
}
function getNetworks() {
- return [{ id: '0', type: Ci.nsIDOMMozNetworkStatsManager.WIFI },
- { id: '1234', type: Ci.nsIDOMMozNetworkStatsManager.MOBILE }];
+ return [{ id: '0', type: Ci.nsINetworkInterface.NETWORK_TYPE_WIFI },
+ { id: '1234', type: Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE }];
}
function compareNetworks(networkA, networkB) {
diff --git a/dom/network/tests/unit_stats/test_networkstats_service.js b/dom/network/tests/unit_stats/test_networkstats_service.js
index 20bbcae61d..e0bf49ea1a 100644
--- a/dom/network/tests/unit_stats/test_networkstats_service.js
+++ b/dom/network/tests/unit_stats/test_networkstats_service.js
@@ -158,12 +158,12 @@ add_test(function test_queue() {
};
// Fill networks with fake network interfaces to enable netd async requests.
- var network = {id: "1234", type: Ci.nsIDOMMozNetworkStatsManager.MOBILE};
+ var network = {id: "1234", type: Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE};
var netId1 = NetworkStatsService.getNetworkId(network.id, network.type);
NetworkStatsService._networks[netId1] = { network: network,
interfaceName: "net1" };
- network = {id: "5678", type: Ci.nsIDOMMozNetworkStatsManager.MOBILE};
+ network = {id: "5678", type: Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE};
var netId2 = NetworkStatsService.getNetworkId(network.id, network.type);
NetworkStatsService._networks[netId2] = { network: network,
interfaceName: "net2" };
diff --git a/dom/permission/tests/mochitest.ini b/dom/permission/tests/mochitest.ini
index 8a527ae287..ed586a0b02 100644
--- a/dom/permission/tests/mochitest.ini
+++ b/dom/permission/tests/mochitest.ini
@@ -18,6 +18,7 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(https not work
[test_tcp-socket.html]
[test_udp-socket.html]
[test_webapps-manage.html]
+skip-if = buildapp != 'b2g' && buildapp != 'mulet'
[test_camera.html]
disabled = disabled until bug 859593 is fixed
[test_keyboard.html]
diff --git a/dom/permission/tests/test_networkstats-manage.html b/dom/permission/tests/test_networkstats-manage.html
index 9eefe6a8a3..4fdc847717 100644
--- a/dom/permission/tests/test_networkstats-manage.html
+++ b/dom/permission/tests/test_networkstats-manage.html
@@ -20,7 +20,7 @@ var gData = [
{
perm: ["networkstats-manage"],
obj: "mozNetworkStats",
- idl: "nsIDOMMozNetworkStatsManager",
+ webidl: "MozNetworkStatsManager",
settings: [["dom.mozNetworkStats.enabled", true]],
},
]
diff --git a/dom/requestsync/tests/mochitest.ini b/dom/requestsync/tests/mochitest.ini
index 96f937990e..1a3018f365 100644
--- a/dom/requestsync/tests/mochitest.ini
+++ b/dom/requestsync/tests/mochitest.ini
@@ -14,7 +14,7 @@ skip-if = os == "android" || toolkit == "gonk"
[test_basic.html]
skip-if = os == "android" || toolkit == "gonk"
[test_basic_app.html]
-skip-if = os == "android" || buildapp == 'b2g' || e10s # mozapps
+skip-if = buildapp != 'mulet' || e10s # mozapps
[test_wakeUp.html]
run-if = buildapp == 'b2g' && toolkit == 'gonk'
[test_runNow.html]
diff --git a/dom/security/test/csp/mochitest.ini b/dom/security/test/csp/mochitest.ini
index fae1bb1c7c..92e061f700 100644
--- a/dom/security/test/csp/mochitest.ini
+++ b/dom/security/test/csp/mochitest.ini
@@ -176,6 +176,7 @@ skip-if = buildapp == 'b2g' #no ssl support
[test_ignore_unsafe_inline.html]
[test_self_none_as_hostname_confusion.html]
[test_bug949549.html]
+skip-if = buildapp != 'b2g' && buildapp != 'mulet'
[test_path_matching.html]
[test_path_matching_redirect.html]
[test_report_uri_missing_in_report_only_header.html]
diff --git a/dom/system/gonk/ril_consts.js b/dom/system/gonk/ril_consts.js
index e3d46b6f65..af5b9d8e10 100644
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -390,6 +390,7 @@ this.GECKO_PREFERRED_NETWORK_TYPE_EVDO_ONLY = "evdo";
this.GECKO_PREFERRED_NETWORK_TYPE_WCDMA_GSM_CDMA_EVDO = "wcdma/gsm/cdma/evdo";
this.GECKO_PREFERRED_NETWORK_TYPE_LTE_CDMA_EVDO = "lte/cdma/evdo";
this.GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA_GSM = "lte/wcdma/gsm";
+this.GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA = "lte/wcdma";
this.GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA_GSM_CDMA_EVDO = "lte/wcdma/gsm/cdma/evdo";
this.GECKO_PREFERRED_NETWORK_TYPE_LTE_ONLY = "lte";
this.RIL_PREFERRED_NETWORK_TYPE_TO_GECKO = [
@@ -404,7 +405,8 @@ this.RIL_PREFERRED_NETWORK_TYPE_TO_GECKO = [
GECKO_PREFERRED_NETWORK_TYPE_LTE_CDMA_EVDO,
GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA_GSM,
GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA_GSM_CDMA_EVDO,
- GECKO_PREFERRED_NETWORK_TYPE_LTE_ONLY
+ GECKO_PREFERRED_NETWORK_TYPE_LTE_ONLY,
+ GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA
];
this.GECKO_SUPPORTED_NETWORK_TYPES_DEFAULT = "gsm,wcdma";
diff --git a/dom/tests/mochitest/fetch/mochitest.ini b/dom/tests/mochitest/fetch/mochitest.ini
index 1282d7ff83..0952705946 100644
--- a/dom/tests/mochitest/fetch/mochitest.ini
+++ b/dom/tests/mochitest/fetch/mochitest.ini
@@ -21,25 +21,34 @@ support-files =
[test_headers_sw_reroute.html]
skip-if = buildapp == 'b2g' # Bug 1137683
[test_headers_mainthread.html]
+skip-if = (e10s && debug && os == 'win')
[test_fetch_app_protocol.html]
+skip-if = (buildapp != 'b2g' && buildapp != 'mulet')
[test_fetch_basic.html]
+skip-if = (e10s && debug && os == 'win')
[test_fetch_basic_sw_reroute.html]
-skip-if = buildapp == 'b2g' # Bug 1137683
+skip-if = buildapp == 'b2g' || (e10s && debug && os == 'win') # Bug 1137683
[test_fetch_basic_http.html]
+skip-if = (e10s && debug && os == 'win')
[test_fetch_basic_http_sw_reroute.html]
-skip-if = e10s || buildapp == 'b2g' # Bug 1173163 for e10s, bug 1137683 for b2g
+skip-if = buildapp == 'b2g' || (e10s && debug && os == 'win') # Bug 1137683
[test_fetch_cors.html]
-skip-if = buildapp == 'b2g' || (toolkit == 'android' && debug) # Bug 1210552 && 1210282
+skip-if = buildapp == 'b2g' || (toolkit == 'android' && debug) || (e10s && debug && os == 'win') # Bug 1210552 && 1210282
[test_fetch_cors_sw_reroute.html]
-skip-if = e10s || buildapp == 'b2g' # Bug 1173163 for e10s, bug 1137683 for b2g
+skip-if = buildapp == 'b2g' || (toolkit == 'android' && debug) # Bug 1210282
[test_formdataparsing.html]
+skip-if = (e10s && debug && os == 'win')
[test_formdataparsing_sw_reroute.html]
-skip-if = buildapp == 'b2g' # Bug 1137683
+skip-if = buildapp == 'b2g' || (e10s && debug && os == 'win') # Bug 1137683
[test_request.html]
+skip-if = (e10s && debug && os == 'win')
[test_request_cache.html]
+skip-if = (e10s && debug && os == 'win')
[test_request_context.html]
+skip-if = (e10s && debug && os == 'win')
[test_request_sw_reroute.html]
-skip-if = buildapp == 'b2g' # Bug 1137683
+skip-if = buildapp == 'b2g' || (e10s && debug && os == 'win') # Bug 1137683
[test_response.html]
+skip-if = (e10s && debug && os == 'win')
[test_response_sw_reroute.html]
-skip-if = buildapp == 'b2g' # Bug 1137683
+skip-if = buildapp == 'b2g' || (e10s && debug && os == 'win') # Bug 1137683
diff --git a/dom/tests/mochitest/general/test_interfaces.html b/dom/tests/mochitest/general/test_interfaces.html
index 8911c86b27..0ef287f403 100644
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -1034,17 +1034,19 @@ var interfaceNamesInGlobalScope =
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SimpleTest", xbl: false},
// IMPORTANT: Do not change this list without review from a DOM peer!
- {name: "SourceBuffer", desktop: true, linux: false, release: false},
+ "SourceBuffer",
// IMPORTANT: Do not change this list without review from a DOM peer!
- {name: "SourceBufferList", desktop: true, linux: false, release: false},
+ "SourceBufferList",
// IMPORTANT: Do not change this list without review from a DOM peer!
- {name: "SpeechSynthesisEvent", b2g: true},
+ {name: "SpeechSynthesisErrorEvent", android: false, nightly: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
- {name: "SpeechSynthesis", b2g: true},
+ {name: "SpeechSynthesisEvent", android: false, nightly: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
- {name: "SpeechSynthesisUtterance", b2g: true},
+ {name: "SpeechSynthesis", android: false, nightly: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
- {name: "SpeechSynthesisVoice", b2g: true},
+ {name: "SpeechSynthesisUtterance", android: false, nightly: true},
+// IMPORTANT: Do not change this list without review from a DOM peer!
+ {name: "SpeechSynthesisVoice", android: false, nightly: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SpecialPowers", xbl: false},
// IMPORTANT: Do not change this list without review from a DOM peer!
diff --git a/dom/tests/mochitest/localstorage/chrome.ini b/dom/tests/mochitest/localstorage/chrome.ini
index 3c4a3362dc..a96487025c 100644
--- a/dom/tests/mochitest/localstorage/chrome.ini
+++ b/dom/tests/mochitest/localstorage/chrome.ini
@@ -5,7 +5,9 @@ support-files =
page_blank.html
[test_app_uninstall.html]
+skip-if = buildapp != 'mulet'
[test_clear_browser_data.html]
+skip-if = buildapp != 'mulet'
[test_localStorageBasePrivateBrowsing_perwindowpb.html]
[test_localStorageFromChrome.xhtml]
[test_localStorageQuotaPrivateBrowsing_perwindowpb.html]
diff --git a/dom/tests/mochitest/localstorage/test_app_uninstall.html b/dom/tests/mochitest/localstorage/test_app_uninstall.html
index 744d3dc8aa..1960326237 100644
--- a/dom/tests/mochitest/localstorage/test_app_uninstall.html
+++ b/dom/tests/mochitest/localstorage/test_app_uninstall.html
@@ -152,7 +152,7 @@ function browserLoadEvent() {
setupStorage(gBrowserStorage.localStorage);
setupStorage(gBrowserStorage.sessionStorage);
- navigator.mozApps.mgmt.getNotInstalled().onsuccess = function() {
+ navigator.mozApps.mgmt.getAll().onsuccess = function() {
for (i in this.result) {
var app = this.result[i];
if (app.manifestURL == gManifestURL) {
diff --git a/dom/tests/mochitest/notification/mochitest.ini b/dom/tests/mochitest/notification/mochitest.ini
index 6b9829779c..539ea03a5e 100644
--- a/dom/tests/mochitest/notification/mochitest.ini
+++ b/dom/tests/mochitest/notification/mochitest.ini
@@ -8,6 +8,6 @@ support-files =
[test_notification_storage.html]
[test_bug931307.html]
[test_notification_resend.html]
-skip-if = e10s # On e10s, faking the app seems to be failing
+skip-if = (buildapp != 'b2g' && buildapp != 'mulet') || e10s # On e10s, faking the app seems to be failing
[test_notification_noresend.html]
skip-if = (toolkit == 'gonk') # Mochitest on Gonk registers an app manifest that messes with the logic
diff --git a/dom/webidl/InterAppMessagePort.webidl b/dom/webidl/InterAppMessagePort.webidl
index 9f23f9b89e..3bcf433fb1 100644
--- a/dom/webidl/InterAppMessagePort.webidl
+++ b/dom/webidl/InterAppMessagePort.webidl
@@ -21,4 +21,5 @@ interface MozInterAppMessagePort : EventTarget {
void close();
attribute EventHandler onmessage;
+ attribute EventHandler onclose;
};
diff --git a/dom/webidl/Location.webidl b/dom/webidl/Location.webidl
index 6f59cb802b..3d6b39ff9f 100644
--- a/dom/webidl/Location.webidl
+++ b/dom/webidl/Location.webidl
@@ -40,10 +40,10 @@ interface Location {
attribute USVString hash;
[Throws, UnsafeInPrerendering]
- void assign(DOMString url);
+ void assign(USVString url);
[Throws, CrossOriginCallable, UnsafeInPrerendering]
- void replace(DOMString url);
+ void replace(USVString url);
// XXXbz there is no forceget argument in the spec! See bug 1037721.
[Throws, UnsafeInPrerendering]
diff --git a/dom/webidl/MediaStreamTrack.webidl b/dom/webidl/MediaStreamTrack.webidl
index fea064e5db..bea5228870 100644
--- a/dom/webidl/MediaStreamTrack.webidl
+++ b/dom/webidl/MediaStreamTrack.webidl
@@ -63,24 +63,26 @@ dictionary MediaTrackConstraints : MediaTrackConstraintSet {
sequence advanced;
};
-interface MediaStreamTrack {
+[Exposed=Window]
+interface MediaStreamTrack : EventTarget {
readonly attribute DOMString kind;
readonly attribute DOMString id;
readonly attribute DOMString label;
attribute boolean enabled;
-// readonly attribute MediaStreamTrackState readyState;
-// readonly attribute SourceTypeEnum sourceType;
-// readonly attribute DOMString sourceId;
-// attribute EventHandler onstarted;
-// attribute EventHandler onmute;
-// attribute EventHandler onunmute;
+// readonly attribute boolean muted;
+// attribute EventHandler onmute;
+// attribute EventHandler onunmute;
+// readonly attribute boolean _readonly;
+// readonly attribute boolean remote;
+// readonly attribute MediaStreamTrackState readyState;
// attribute EventHandler onended;
-// any getConstraint (DOMString constraintName, optional boolean mandatory = false);
-// void setConstraint (DOMString constraintName, any constraintValue, optional boolean mandatory = false);
-// MediaTrackConstraints? constraints ();
-// void applyConstraints (MediaTrackConstraints constraints);
-// void prependConstraint (DOMString constraintName, any constraintValue);
-// void appendConstraint (DOMString constraintName, any constraintValue);
-// attribute EventHandler onoverconstrained;
+// MediaStreamTrack clone ();
void stop ();
+// MediaTrackCapabilities getCapabilities ();
+// MediaTrackConstraints getConstraints ();
+// MediaTrackSettings getSettings ();
+
+ [Throws]
+ Promise applyConstraints (optional MediaTrackConstraints constraints);
+// attribute EventHandler onoverconstrained;
};
diff --git a/dom/webidl/MozMobileConnection.webidl b/dom/webidl/MozMobileConnection.webidl
index 1d9c9d4047..13ade08dcc 100644
--- a/dom/webidl/MozMobileConnection.webidl
+++ b/dom/webidl/MozMobileConnection.webidl
@@ -9,7 +9,7 @@ enum MobilePreferredNetworkType {"wcdma/gsm", "gsm", "wcdma", "wcdma/gsm-auto",
"cdma/evdo", "cdma", "evdo",
"wcdma/gsm/cdma/evdo", "lte/cdma/evdo",
"lte/wcdma/gsm", "lte/wcdma/gsm/cdma/evdo",
- "lte"};
+ "lte", "lte/wcdma"};
enum MobileRoamingMode {"home", "affiliated", "any"};
[Pref="dom.mobileconnection.enabled"]
@@ -190,7 +190,7 @@ interface MozMobileConnection : EventTarget
* result will be a string indicating the current preferred network type.
* The value will be either 'wcdma/gsm', 'gsm', 'wcdma', 'wcdma/gsm-auto',
* 'cdma/evdo', 'cdma', 'evdo', 'wcdma/gsm/cdma/evdo', 'lte/cdma/evdo',
- * 'lte/wcdma/gsm', 'lte/wcdma/gsm/cdma/evdo' or 'lte'.
+ * 'lte/wcdma/gsm', 'lte/wcdma/gsm/cdma/evdo', 'lte' or 'lte/wcdma'.
*
* Otherwise, the request's onerror will be called, and the request's error
* will be either 'RadioNotAvailable', 'RequestNotSupported',
diff --git a/dom/webidl/MozNetworkStats.webidl b/dom/webidl/MozNetworkStats.webidl
index eb9713b617..27243f3ba2 100644
--- a/dom/webidl/MozNetworkStats.webidl
+++ b/dom/webidl/MozNetworkStats.webidl
@@ -14,15 +14,15 @@ dictionary NetworkStatsGetOptions
* Note that, these two options cannot be specified at the same time for now;
* others, an NS_ERROR_NOT_IMPLMENTED exception will be thrown.
*/
- DOMString appManifestURL;
- DOMString serviceType;
+ DOMString? appManifestURL = null;
+ DOMString serviceType = "";
/**
* If it is set as true, only the browsing traffic, which is generated from
* the mozbrowser iframe element within an app, is returned in result.
* If it is set as false or not set, the total traffic, which is generated
* from both the mozapp and mozbrowser iframe elements, is returned.
*/
- boolean browsingTrafficOnly;
+ boolean browsingTrafficOnly = false;
};
dictionary NetworkStatsAlarmOptions
diff --git a/dom/network/interfaces/nsIDOMNetworkStatsManager.idl b/dom/webidl/MozNetworkStatsManager.webidl
similarity index 65%
rename from dom/network/interfaces/nsIDOMNetworkStatsManager.idl
rename to dom/webidl/MozNetworkStatsManager.webidl
index 9db848af10..0295e40787 100644
--- a/dom/network/interfaces/nsIDOMNetworkStatsManager.idl
+++ b/dom/webidl/MozNetworkStatsManager.webidl
@@ -1,14 +1,14 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
-#include "nsISupports.idl"
-
-interface nsIDOMDOMRequest;
-
-[scriptable, uuid(72c4e583-389d-4d1b-9424-702feabb6055)]
-interface nsIDOMMozNetworkStatsManager : nsISupports
-{
+[NavigatorProperty="mozNetworkStats",
+ JSImplementation="@mozilla.org/networkStatsManager;1",
+ CheckAnyPermissions="networkstats-manage",
+ Pref="dom.mozNetworkStats.enabled"]
+interface MozNetworkStatsManager {
/**
* Constants for known interface types.
*/
@@ -21,12 +21,12 @@ interface nsIDOMMozNetworkStatsManager : nsISupports
* If options is provided, per-app or per-system service usage will be
* retrieved; otherwise the target will be overall system usage.
*
- * If success, the request result will be an nsIDOMMozNetworkStats object.
+ * If success, the request result will be an MozNetworkStats object.
*/
- nsIDOMDOMRequest getSamples(in nsISupports network,
- in jsval start,
- in jsval end,
- [optional] in jsval options /* NetworkStatsGetOptions */);
+ DOMRequest getSamples(MozNetworkStatsInterface network,
+ Date start,
+ Date end,
+ optional NetworkStatsGetOptions options);
/**
* Install an alarm on a network. The network must be in the return of
@@ -39,9 +39,9 @@ interface nsIDOMMozNetworkStatsManager : nsISupports
*
* If success, the |result| field of the DOMRequest keeps the alarm Id.
*/
- nsIDOMDOMRequest addAlarm(in nsISupports network,
- in long long threshold,
- [optional] in jsval options /* NetworkStatsAlarmOptions */);
+ DOMRequest addAlarm(MozNetworkStatsInterface network,
+ long long threshold,
+ optional NetworkStatsAlarmOptions options);
/**
* Obtain all alarms for those networks returned by getAvailableNetworks().
@@ -55,33 +55,33 @@ interface nsIDOMMozNetworkStatsManager : nsISupports
* - threshold
* - data
*/
- nsIDOMDOMRequest getAllAlarms([optional] in nsISupports network);
+ DOMRequest getAllAlarms(optional MozNetworkStatsInterface network);
/**
* Remove all network alarms. If an |alarmId| is provided, then only that
* alarm is removed.
*/
- nsIDOMDOMRequest removeAlarms([optional] in long alarmId);
+ DOMRequest removeAlarms(optional unsigned long alarmId = 0);
/**
* Remove all stats related with the provided network from DB.
*/
- nsIDOMDOMRequest clearStats(in nsISupports network);
+ DOMRequest clearStats(MozNetworkStatsInterface network);
/**
* Remove all stats in the database.
*/
- nsIDOMDOMRequest clearAllStats();
+ DOMRequest clearAllStats();
/**
* Return available networks that used to be saved in the database.
*/
- nsIDOMDOMRequest getAvailableNetworks(); // array of MozNetworkStatsInterface.
+ DOMRequest getAvailableNetworks(); // array of MozNetworkStatsInterface.
/**
* Return available service types that used to be saved in the database.
*/
- nsIDOMDOMRequest getAvailableServiceTypes(); // array of string.
+ DOMRequest getAvailableServiceTypes(); // array of string.
/**
* Minimum time in milliseconds between samples stored in the database.
diff --git a/dom/webidl/Navigator.webidl b/dom/webidl/Navigator.webidl
index b70832d9af..6c30c12cf2 100644
--- a/dom/webidl/Navigator.webidl
+++ b/dom/webidl/Navigator.webidl
@@ -54,8 +54,10 @@ interface NavigatorID {
[NoInterfaceObject, Exposed=(Window,Worker)]
interface NavigatorLanguage {
- // These 2 values are cached. They are updated when pref
- // intl.accept_languages is changed.
+ // These two attributes are cached because this interface is also implemented
+ // by Workernavigator and this way we don't have to go back to the
+ // main-thread from the worker thread anytime we need to retrieve them. They
+ // are updated when pref intl.accept_languages is changed.
[Pure, Cached]
readonly attribute DOMString? language;
@@ -98,7 +100,7 @@ interface NavigatorFeatures {
};
partial interface Navigator {
- [Throws, Pref="dom.permissions.enabled"]
+ [Throws]
readonly attribute Permissions permissions;
};
@@ -188,7 +190,7 @@ Navigator implements NavigatorMobileId;
// nsIDOMNavigator
partial interface Navigator {
- [Throws]
+ [Throws, Constant, Cached]
readonly attribute DOMString oscpu;
// WebKit/Blink support this; Trident/Presto do not.
readonly attribute DOMString vendor;
@@ -198,7 +200,7 @@ partial interface Navigator {
readonly attribute DOMString productSub;
// WebKit/Blink/Trident/Presto support this.
readonly attribute boolean cookieEnabled;
- [Throws]
+ [Throws, Constant, Cached]
readonly attribute DOMString buildID;
[Throws, CheckAnyPermissions="power", UnsafeInPrerendering]
readonly attribute MozPowerManager mozPower;
@@ -418,7 +420,7 @@ partial interface Navigator {
// Service Workers/Navigation Controllers
partial interface Navigator {
- [Func="ServiceWorkerContainer::IsEnabled"]
+ [Func="ServiceWorkerContainer::IsEnabled", SameObject]
readonly attribute ServiceWorkerContainer serviceWorker;
};
diff --git a/dom/webidl/NotificationEvent.webidl b/dom/webidl/NotificationEvent.webidl
index e92e33a191..b5099e6a21 100644
--- a/dom/webidl/NotificationEvent.webidl
+++ b/dom/webidl/NotificationEvent.webidl
@@ -11,7 +11,7 @@
* related or neighboring rights to this work.
*/
-[Constructor(DOMString type, optional NotificationEventInit eventInitDict),
+[Constructor(DOMString type, NotificationEventInit eventInitDict),
Exposed=ServiceWorker,Func="mozilla::dom::Notification::PrefEnabled"]
interface NotificationEvent : ExtendableEvent {
readonly attribute Notification notification;
diff --git a/dom/webidl/PermissionStatus.webidl b/dom/webidl/PermissionStatus.webidl
index 27ae490c39..3abfd66f40 100644
--- a/dom/webidl/PermissionStatus.webidl
+++ b/dom/webidl/PermissionStatus.webidl
@@ -13,8 +13,7 @@ enum PermissionState {
"prompt"
};
-[Exposed=(Window),
- Pref="dom.permissions.enabled"]
+[Exposed=(Window)]
interface PermissionStatus : EventTarget {
readonly attribute PermissionState state;
attribute EventHandler onchange;
diff --git a/dom/webidl/Permissions.webidl b/dom/webidl/Permissions.webidl
index fa1f6d874a..0c7f8f30d0 100644
--- a/dom/webidl/Permissions.webidl
+++ b/dom/webidl/Permissions.webidl
@@ -22,8 +22,7 @@ dictionary PushPermissionDescriptor : PermissionDescriptor {
boolean userVisible = false;
};
-[Exposed=(Window),
- Pref="dom.permissions.enabled"]
+[Exposed=(Window)]
interface Permissions {
[Throws]
Promise query(object permission);
diff --git a/dom/webidl/SpeechSynthesisErrorEvent.webidl b/dom/webidl/SpeechSynthesisErrorEvent.webidl
new file mode 100644
index 0000000000..1388755d31
--- /dev/null
+++ b/dom/webidl/SpeechSynthesisErrorEvent.webidl
@@ -0,0 +1,36 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * http://dvcs.w3.org/hg/speech-api/raw-file/tip/speechapi.html
+ *
+ * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+enum SpeechSynthesisErrorCode {
+ "canceled",
+ "interrupted",
+ "audio-busy",
+ "audio-hardware",
+ "network",
+ "synthesis-unavailable",
+ "synthesis-failed",
+ "language-unavailable",
+ "voice-unavailable",
+ "text-too-long",
+ "invalid-argument",
+};
+
+[Constructor(DOMString type, SpeechSynthesisErrorEventInit eventInitDict),
+ Pref="media.webspeech.synth.enabled"]
+interface SpeechSynthesisErrorEvent : SpeechSynthesisEvent {
+ readonly attribute SpeechSynthesisErrorCode error;
+};
+
+dictionary SpeechSynthesisErrorEventInit : SpeechSynthesisEventInit
+{
+ required SpeechSynthesisErrorCode error;
+};
diff --git a/dom/webidl/SpeechSynthesisEvent.webidl b/dom/webidl/SpeechSynthesisEvent.webidl
index 029eeb2476..a5f8b3c2b3 100644
--- a/dom/webidl/SpeechSynthesisEvent.webidl
+++ b/dom/webidl/SpeechSynthesisEvent.webidl
@@ -10,10 +10,11 @@
* liability, trademark and document use rules apply.
*/
-[Constructor(DOMString type, optional SpeechSynthesisEventInit eventInitDict),
+[Constructor(DOMString type, SpeechSynthesisEventInit eventInitDict),
Pref="media.webspeech.synth.enabled"]
interface SpeechSynthesisEvent : Event
{
+ readonly attribute SpeechSynthesisUtterance utterance;
readonly attribute unsigned long charIndex;
readonly attribute float elapsedTime;
readonly attribute DOMString? name;
@@ -21,6 +22,7 @@ interface SpeechSynthesisEvent : Event
dictionary SpeechSynthesisEventInit : EventInit
{
+ required SpeechSynthesisUtterance utterance;
unsigned long charIndex = 0;
float elapsedTime = 0;
DOMString name = "";
diff --git a/dom/webidl/TreeColumn.webidl b/dom/webidl/TreeColumn.webidl
index a4e02f5791..6d843a078a 100644
--- a/dom/webidl/TreeColumn.webidl
+++ b/dom/webidl/TreeColumn.webidl
@@ -25,6 +25,7 @@ interface TreeColumn {
const short TYPE_TEXT = 1;
const short TYPE_CHECKBOX = 2;
const short TYPE_PROGRESSMETER = 3;
+ const short TYPE_PASSWORD = 4;
readonly attribute short type;
TreeColumn? getNext();
diff --git a/dom/webidl/WebGL2RenderingContext.webidl b/dom/webidl/WebGL2RenderingContext.webidl
index 4f7cbb20f4..3cfd1400c7 100644
--- a/dom/webidl/WebGL2RenderingContext.webidl
+++ b/dom/webidl/WebGL2RenderingContext.webidl
@@ -236,7 +236,6 @@ interface WebGL2RenderingContext : WebGLRenderingContext
const GLenum RGB8_SNORM = 0x8F96;
const GLenum RGBA8_SNORM = 0x8F97;
const GLenum SIGNED_NORMALIZED = 0x8F9C;
- const GLenum PRIMITIVE_RESTART_FIXED_INDEX = 0x8D69;
const GLenum COPY_READ_BUFFER = 0x8F36;
const GLenum COPY_WRITE_BUFFER = 0x8F37;
const GLenum COPY_READ_BUFFER_BINDING = 0x8F36; /* Same as COPY_READ_BUFFER */
@@ -289,10 +288,6 @@ interface WebGL2RenderingContext : WebGLRenderingContext
const GLenum ANY_SAMPLES_PASSED_CONSERVATIVE = 0x8D6A;
const GLenum SAMPLER_BINDING = 0x8919;
const GLenum RGB10_A2UI = 0x906F;
- const GLenum TEXTURE_SWIZZLE_R = 0x8E42;
- const GLenum TEXTURE_SWIZZLE_G = 0x8E43;
- const GLenum TEXTURE_SWIZZLE_B = 0x8E44;
- const GLenum TEXTURE_SWIZZLE_A = 0x8E45;
const GLenum GREEN = 0x1904;
const GLenum BLUE = 0x1905;
const GLenum INT_2_10_10_10_REV = 0x8D9F;
diff --git a/dom/webidl/Window.webidl b/dom/webidl/Window.webidl
index 2c4d2bee0b..922e688447 100644
--- a/dom/webidl/Window.webidl
+++ b/dom/webidl/Window.webidl
@@ -69,7 +69,7 @@ typedef any Transferable;
#ifdef HAVE_SIDEBAR
[Replaceable, Throws] readonly attribute External external;
#endif
- [Throws] readonly attribute ApplicationCache applicationCache;
+ [Throws, Pref="browser.cache.offline.enable"] readonly attribute ApplicationCache applicationCache;
// user prompts
[Throws, UnsafeInPrerendering] void alert();
@@ -269,7 +269,7 @@ Window implements WindowModal;
// https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#self-caches
partial interface Window {
-[Throws, Func="mozilla::dom::cache::CacheStorage::PrefEnabled"]
+[Throws, Func="mozilla::dom::cache::CacheStorage::PrefEnabled", SameObject]
readonly attribute CacheStorage caches;
};
diff --git a/dom/webidl/Worker.webidl b/dom/webidl/Worker.webidl
index 6376fedfa6..158a502d60 100644
--- a/dom/webidl/Worker.webidl
+++ b/dom/webidl/Worker.webidl
@@ -14,7 +14,7 @@
[Constructor(DOMString scriptURL),
Func="mozilla::dom::workers::WorkerPrivate::WorkerAvailable",
- Exposed=(Window,Worker,System)]
+ Exposed=(Window,DedicatedWorker,SharedWorker,System)]
interface Worker : EventTarget {
void terminate();
@@ -28,6 +28,6 @@ Worker implements AbstractWorker;
[Constructor(DOMString scriptURL),
Func="mozilla::dom::workers::ChromeWorkerPrivate::WorkerAvailable",
- Exposed=(Window,Worker,System)]
+ Exposed=(Window,DedicatedWorker,SharedWorker,System)]
interface ChromeWorker : Worker {
};
diff --git a/dom/webidl/WorkerGlobalScope.webidl b/dom/webidl/WorkerGlobalScope.webidl
index f56eb40802..3ea893d73a 100644
--- a/dom/webidl/WorkerGlobalScope.webidl
+++ b/dom/webidl/WorkerGlobalScope.webidl
@@ -40,7 +40,7 @@ partial interface WorkerGlobalScope {
// https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#self-caches
partial interface WorkerGlobalScope {
-[Throws, Func="mozilla::dom::cache::CacheStorage::PrefEnabled"]
+[Throws, Func="mozilla::dom::cache::CacheStorage::PrefEnabled", SameObject]
readonly attribute CacheStorage caches;
};
diff --git a/dom/webidl/XMLHttpRequest.webidl b/dom/webidl/XMLHttpRequest.webidl
index d5cf4962cb..9af72f9c6d 100644
--- a/dom/webidl/XMLHttpRequest.webidl
+++ b/dom/webidl/XMLHttpRequest.webidl
@@ -54,7 +54,7 @@ dictionary MozXMLHttpRequestParameters
// c = new(window.ActiveXObject || XMLHttpRequest)("Microsoft.XMLHTTP")
// To handle that, we need a constructor that takes a string.
Constructor(DOMString ignored),
- Exposed=(Window,Worker)]
+ Exposed=(Window,DedicatedWorker,SharedWorker)]
interface XMLHttpRequest : XMLHttpRequestEventTarget {
// event handler
attribute EventHandler onreadystatechange;
diff --git a/dom/webidl/XMLHttpRequestEventTarget.webidl b/dom/webidl/XMLHttpRequestEventTarget.webidl
index 39c2c53f59..f16634355b 100644
--- a/dom/webidl/XMLHttpRequestEventTarget.webidl
+++ b/dom/webidl/XMLHttpRequestEventTarget.webidl
@@ -10,7 +10,7 @@
* liability, trademark and document use rules apply.
*/
-[Exposed=(Window,Worker)]
+[Exposed=(Window,DedicatedWorker,SharedWorker)]
interface XMLHttpRequestEventTarget : EventTarget {
// event handlers
[SetterThrows=Workers, GetterThrows=Workers]
diff --git a/dom/webidl/XMLHttpRequestUpload.webidl b/dom/webidl/XMLHttpRequestUpload.webidl
index 002b892c26..cbb8728b7a 100644
--- a/dom/webidl/XMLHttpRequestUpload.webidl
+++ b/dom/webidl/XMLHttpRequestUpload.webidl
@@ -10,7 +10,7 @@
* liability, trademark and document use rules apply.
*/
-[Exposed=(Window,Worker)]
+[Exposed=(Window,DedicatedWorker,SharedWorker)]
interface XMLHttpRequestUpload : XMLHttpRequestEventTarget {
};
diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build
index 3c947501c3..92232b5935 100644
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -32,7 +32,6 @@ WEBIDL_FILES = [
'AnonymousContent.webidl',
'AppInfo.webidl',
'AppNotificationServiceOptions.webidl',
- 'Apps.webidl',
'APZTestData.webidl',
'ArchiveReader.webidl',
'ArchiveRequest.webidl',
@@ -631,7 +630,7 @@ if CONFIG['MOZ_WEBRTC']:
'PeerConnectionImplEnums.webidl',
'PeerConnectionObserver.webidl',
'PeerConnectionObserverEnums.webidl',
- 'RTCCertificate.webidl',
+ 'RTCCertificate.webidl',
'RTCConfiguration.webidl',
'RTCIceCandidate.webidl',
'RTCIdentityAssertion.webidl',
@@ -656,6 +655,7 @@ if CONFIG['MOZ_WEBSPEECH']:
'SpeechRecognitionResult.webidl',
'SpeechRecognitionResultList.webidl',
'SpeechSynthesis.webidl',
+ 'SpeechSynthesisErrorEvent.webidl',
'SpeechSynthesisEvent.webidl',
'SpeechSynthesisUtterance.webidl',
'SpeechSynthesisVoice.webidl',
@@ -673,7 +673,6 @@ WEBIDL_FILES += [
'DeviceStorageChangeEvent.webidl',
'DOMTransactionEvent.webidl',
'HashChangeEvent.webidl',
- 'MozApplicationEvent.webidl',
'MozSettingsEvent.webidl',
'PageTransitionEvent.webidl',
'PopStateEvent.webidl',
@@ -751,6 +750,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
'MozNetworkStatsAlarm.webidl',
'MozNetworkStatsData.webidl',
'MozNetworkStatsInterface.webidl',
+ 'MozNetworkStatsManager.webidl',
'MozSpeakerManager.webidl',
'MozWifiCapabilities.webidl',
'MozWifiManager.webidl',
@@ -795,7 +795,6 @@ GENERATED_EVENTS_WEBIDL_FILES = [
'IccChangeEvent.webidl',
'ImageCaptureErrorEvent.webidl',
'MediaStreamEvent.webidl',
- 'MozApplicationEvent.webidl',
'MozCellBroadcastEvent.webidl',
'MozClirModeEvent.webidl',
'MozContactChangeEvent.webidl',
@@ -845,6 +844,7 @@ if CONFIG['MOZ_WEBRTC']:
if CONFIG['MOZ_WEBSPEECH']:
GENERATED_EVENTS_WEBIDL_FILES += [
'SpeechRecognitionEvent.webidl',
+ 'SpeechSynthesisErrorEvent.webidl',
'SpeechSynthesisEvent.webidl',
]
@@ -906,5 +906,10 @@ if CONFIG['MOZ_PAY']:
if CONFIG['MOZ_B2G']:
WEBIDL_FILES += [
- 'Identity.webidl'
+ 'Apps.webidl',
+ 'Identity.webidl',
+ 'MozApplicationEvent.webidl'
+ ]
+ GENERATED_EVENTS_WEBIDL_FILES += [
+ 'MozApplicationEvent.webidl'
]
diff --git a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
index 4ab9880413..ec71a93baf 100644
--- a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
+++ b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
@@ -190,12 +190,6 @@ var interfaceNamesInGlobalScope =
"TextDecoder",
// IMPORTANT: Do not change this list without review from a DOM peer!
"TextEncoder",
-// IMPORTANT: Do not change this list without review from a DOM peer!
- "XMLHttpRequest",
-// IMPORTANT: Do not change this list without review from a DOM peer!
- "XMLHttpRequestEventTarget",
-// IMPORTANT: Do not change this list without review from a DOM peer!
- "XMLHttpRequestUpload",
// IMPORTANT: Do not change this list without review from a DOM peer!
"URL",
// IMPORTANT: Do not change this list without review from a DOM peer!
diff --git a/extensions/cookie/test/chrome.ini b/extensions/cookie/test/chrome.ini
index 76bb729f77..99dce343dd 100644
--- a/extensions/cookie/test/chrome.ini
+++ b/extensions/cookie/test/chrome.ini
@@ -3,5 +3,8 @@ skip-if = buildapp == 'b2g'
support-files = channel_utils.js
[test_app_uninstall_cookies.html]
+skip-if = buildapp != 'mulet'
[test_app_uninstall_permissions.html]
+skip-if = buildapp != 'mulet'
+
[test_permissionmanager_app_isolation.html]
diff --git a/extensions/cookie/test/test_app_uninstall_cookies.html b/extensions/cookie/test/test_app_uninstall_cookies.html
index 165bd27942..14a2499e63 100644
--- a/extensions/cookie/test/test_app_uninstall_cookies.html
+++ b/extensions/cookie/test/test_app_uninstall_cookies.html
@@ -158,8 +158,7 @@ function checkCookie() {
gCurrentCookiesCount = getCookiesCount() - appCookiesCount;
- // Not installed means not installed as native app.
- navigator.mozApps.mgmt.getNotInstalled().onsuccess = function() {
+ navigator.mozApps.mgmt.getAll().onsuccess = function() {
for (i in this.result) {
var app = this.result[i];
if (app.manifestURL == gManifestURL) {
diff --git a/extensions/cookie/test/test_app_uninstall_permissions.html b/extensions/cookie/test/test_app_uninstall_permissions.html
index 63455db011..6b69df6776 100644
--- a/extensions/cookie/test/test_app_uninstall_permissions.html
+++ b/extensions/cookie/test/test_app_uninstall_permissions.html
@@ -60,12 +60,17 @@ SimpleTest.registerCleanupFunction(() =>
var gManifestURL = "http://www.example.com/chrome/dom/tests/mochitest/webapps/apps/basic.webapp";
+// Get the permission count before installing the app so we can compare it to
+// the permission count after uninstalling the app.
+var currentPermissionCount = getPermissionCountForApp(-1);
+
function onInstall() {
var testAppId = appsService.getAppLocalIdByManifestURL(gManifestURL);
- is(getPermissionCountForApp(testAppId), 0, "App should have no permission");
-
- var currentPermissionCount = getPermissionCountForApp(-1);
+ // PermissionsManager.installPermissions gets run during the install process,
+ // and it adds the "indexedDB" permission by default, so the app should have
+ // that permission.
+ is(getPermissionCountForApp(testAppId), 1, "App should have 1 permission");
var attrs = {appId: testAppId};
var principal = secMan.createCodebasePrincipal(ioService.newURI("http://www.example.com", null, null),
@@ -85,10 +90,9 @@ function onInstall() {
attrs);
permManager.addFromPrincipal(principal, "foobar", Ci.nsIPermissionManager.ALLOW_ACTION);
- is(getPermissionCountForApp(testAppId), 5, "App should have 5 permissions");
+ is(getPermissionCountForApp(testAppId), 6, "App should have 6 permissions");
- // Not installed means not installed as native app.
- navigator.mozApps.mgmt.getNotInstalled().onsuccess = function() {
+ navigator.mozApps.mgmt.getAll().onsuccess = function() {
for (i in this.result) {
var app = this.result[i];
if (app.manifestURL == gManifestURL) {
diff --git a/gfx/docs/index.rst b/gfx/docs/index.rst
new file mode 100644
index 0000000000..c6621c81ab
--- /dev/null
+++ b/gfx/docs/index.rst
@@ -0,0 +1,9 @@
+========
+Graphics
+========
+
+The graphics team's documentation is currently using doxygen. We're tracking the work to integrate it better at https://bugzilla.mozilla.org/show_bug.cgi?id=1150232.
+
+For now you can read the graphics source code documentation here:
+
+http://people.mozilla.org/~bgirard/doxygen/gfx/
diff --git a/gfx/moz.build b/gfx/moz.build
index ccc9e4a410..2ed70f83a8 100644
--- a/gfx/moz.build
+++ b/gfx/moz.build
@@ -31,3 +31,4 @@ if CONFIG['ENABLE_TESTS']:
TEST_DIRS += ['tests']
+SPHINX_TREES['gfx'] = 'docs'
diff --git a/gfx/src/nsFontMetrics.cpp b/gfx/src/nsFontMetrics.cpp
index 311d698ab2..9b18e9882d 100644
--- a/gfx/src/nsFontMetrics.cpp
+++ b/gfx/src/nsFontMetrics.cpp
@@ -81,7 +81,7 @@ private:
class StubPropertyProvider : public gfxTextRun::PropertyProvider {
public:
- virtual void GetHyphenationBreaks(uint32_t aStart, uint32_t aLength,
+ virtual void GetHyphenationBreaks(gfxTextRun::Range aRange,
bool* aBreakBefore) {
NS_ERROR("This shouldn't be called because we never call BreakAndMeasureText");
}
@@ -101,8 +101,7 @@ public:
NS_ERROR("This shouldn't be called because we never enable hyphens");
return 60;
}
- virtual void GetSpacing(uint32_t aStart, uint32_t aLength,
- Spacing* aSpacing) {
+ virtual void GetSpacing(gfxTextRun::Range aRange, Spacing* aSpacing) {
NS_ERROR("This shouldn't be called because we never enable spacing");
}
};
@@ -325,8 +324,11 @@ nsFontMetrics::GetWidth(const char* aString, uint32_t aLength,
StubPropertyProvider provider;
AutoTextRun textRun(this, aDrawTarget, aString, aLength);
- return textRun.get() ?
- NSToCoordRound(textRun->GetAdvanceWidth(0, aLength, &provider)) : 0;
+ if (textRun.get()) {
+ return NSToCoordRound(
+ textRun->GetAdvanceWidth(Range(0, aLength), &provider));
+ }
+ return 0;
}
nscoord
@@ -341,8 +343,11 @@ nsFontMetrics::GetWidth(const char16_t* aString, uint32_t aLength,
StubPropertyProvider provider;
AutoTextRun textRun(this, aDrawTarget, aString, aLength);
- return textRun.get() ?
- NSToCoordRound(textRun->GetAdvanceWidth(0, aLength, &provider)) : 0;
+ if (textRun.get()) {
+ return NSToCoordRound(
+ textRun->GetAdvanceWidth(Range(0, aLength), &provider));
+ }
+ return 0;
}
// Draw a string using this font handle on the surface passed in.
@@ -360,15 +365,17 @@ nsFontMetrics::DrawString(const char *aString, uint32_t aLength,
return;
}
gfxPoint pt(aX, aY);
+ Range range(0, aLength);
if (mTextRunRTL) {
if (mVertical) {
- pt.y += textRun->GetAdvanceWidth(0, aLength, &provider);
+ pt.y += textRun->GetAdvanceWidth(range, &provider);
} else {
- pt.x += textRun->GetAdvanceWidth(0, aLength, &provider);
+ pt.x += textRun->GetAdvanceWidth(range, &provider);
}
}
- textRun->Draw(aContext->ThebesContext(), pt, DrawMode::GLYPH_FILL, 0, aLength,
- &provider, nullptr, nullptr);
+ gfxTextRun::DrawParams params(aContext->ThebesContext());
+ params.provider = &provider;
+ textRun->Draw(range, pt, params);
}
void
@@ -386,15 +393,17 @@ nsFontMetrics::DrawString(const char16_t* aString, uint32_t aLength,
return;
}
gfxPoint pt(aX, aY);
+ Range range(0, aLength);
if (mTextRunRTL) {
if (mVertical) {
- pt.y += textRun->GetAdvanceWidth(0, aLength, &provider);
+ pt.y += textRun->GetAdvanceWidth(range, &provider);
} else {
- pt.x += textRun->GetAdvanceWidth(0, aLength, &provider);
+ pt.x += textRun->GetAdvanceWidth(range, &provider);
}
}
- textRun->Draw(aContext->ThebesContext(), pt, DrawMode::GLYPH_FILL, 0, aLength,
- &provider, nullptr, nullptr);
+ gfxTextRun::DrawParams params(aContext->ThebesContext());
+ params.provider = &provider;
+ textRun->Draw(range, pt, params);
}
static nsBoundingMetrics
@@ -409,8 +418,8 @@ GetTextBoundingMetrics(nsFontMetrics* aMetrics, const char16_t* aString,
AutoTextRun textRun(aMetrics, aDrawTarget, aString, aLength);
nsBoundingMetrics m;
if (textRun.get()) {
- gfxTextRun::Metrics theMetrics =
- textRun->MeasureText(0, aLength, aType, aDrawTarget, &provider);
+ gfxTextRun::Metrics theMetrics = textRun->MeasureText(
+ gfxTextRun::Range(0, aLength), aType, aDrawTarget, &provider);
m.leftBearing = NSToCoordFloor( theMetrics.mBoundingBox.X());
m.rightBearing = NSToCoordCeil( theMetrics.mBoundingBox.XMost());
diff --git a/gfx/src/nsFontMetrics.h b/gfx/src/nsFontMetrics.h
index cecdf103f7..0c38818f8b 100644
--- a/gfx/src/nsFontMetrics.h
+++ b/gfx/src/nsFontMetrics.h
@@ -46,6 +46,7 @@ struct nsBoundingMetrics;
class nsFontMetrics final
{
public:
+ typedef gfxTextRun::Range Range;
typedef mozilla::gfx::DrawTarget DrawTarget;
nsFontMetrics();
diff --git a/gfx/thebes/gfxDWriteFonts.cpp b/gfx/thebes/gfxDWriteFonts.cpp
index 22045569ac..2594a6a322 100644
--- a/gfx/thebes/gfxDWriteFonts.cpp
+++ b/gfx/thebes/gfxDWriteFonts.cpp
@@ -546,8 +546,6 @@ gfxDWriteFont::GetCairoScaledFont()
cairo_dwrite_scaled_font_allow_manual_show_glyphs(mScaledFont,
mAllowManualShowGlyphs);
- gfxDWriteFontEntry *fe =
- static_cast(mFontEntry.get());
cairo_dwrite_scaled_font_set_force_GDI_classic(mScaledFont,
GetForceGDIClassic());
}
diff --git a/gfx/thebes/gfxFcPlatformFontList.cpp b/gfx/thebes/gfxFcPlatformFontList.cpp
index eea018aee1..8413496c63 100644
--- a/gfx/thebes/gfxFcPlatformFontList.cpp
+++ b/gfx/thebes/gfxFcPlatformFontList.cpp
@@ -184,132 +184,6 @@ MapFcWidth(int aFcWidth)
return NS_FONT_STRETCH_ULTRA_EXPANDED;
}
-// mapping of moz lang groups ==> default lang
-struct MozLangGroupData {
- nsIAtom* const& mozLangGroup;
- const char *defaultLang;
-};
-
-const MozLangGroupData MozLangGroups[] = {
- { nsGkAtoms::x_western, "en" },
- { nsGkAtoms::x_cyrillic, "ru" },
- { nsGkAtoms::x_devanagari, "hi" },
- { nsGkAtoms::x_tamil, "ta" },
- { nsGkAtoms::x_armn, "hy" },
- { nsGkAtoms::x_beng, "bn" },
- { nsGkAtoms::x_cans, "iu" },
- { nsGkAtoms::x_ethi, "am" },
- { nsGkAtoms::x_geor, "ka" },
- { nsGkAtoms::x_gujr, "gu" },
- { nsGkAtoms::x_guru, "pa" },
- { nsGkAtoms::x_khmr, "km" },
- { nsGkAtoms::x_knda, "kn" },
- { nsGkAtoms::x_mlym, "ml" },
- { nsGkAtoms::x_orya, "or" },
- { nsGkAtoms::x_sinh, "si" },
- { nsGkAtoms::x_tamil, "ta" },
- { nsGkAtoms::x_telu, "te" },
- { nsGkAtoms::x_tibt, "bo" },
- { nsGkAtoms::Unicode, 0 }
-};
-
-bool
-gfxFcPlatformFontList::TryLangForGroup(const nsACString& aOSLang,
- nsIAtom* aLangGroup,
- nsACString& aFcLang)
-{
- // Truncate at '.' or '@' from aOSLang, and convert '_' to '-'.
- // aOSLang is in the form "language[_territory][.codeset][@modifier]".
- // fontconfig takes languages in the form "language-territory".
- // nsILanguageAtomService takes languages in the form language-subtag,
- // where subtag may be a territory. fontconfig and nsILanguageAtomService
- // handle case-conversion for us.
- const char *pos, *end;
- aOSLang.BeginReading(pos);
- aOSLang.EndReading(end);
- aFcLang.Truncate();
- while (pos < end) {
- switch (*pos) {
- case '.':
- case '@':
- end = pos;
- break;
- case '_':
- aFcLang.Append('-');
- break;
- default:
- aFcLang.Append(*pos);
- }
- ++pos;
- }
-
- nsILanguageAtomService* langService = GetLangService();
- nsIAtom *atom = langService->LookupLanguage(aFcLang);
- return atom == aLangGroup;
-}
-
-void
-gfxFcPlatformFontList::GetSampleLangForGroup(nsIAtom* aLanguage,
- nsACString& aLangStr)
-{
- aLangStr.Truncate();
- if (!aLanguage) {
- return;
- }
-
- // set up lang string
- const MozLangGroupData *mozLangGroup = nullptr;
-
- // -- look it up in the list of moz lang groups
- for (unsigned int i = 0; i < ArrayLength(MozLangGroups); ++i) {
- if (aLanguage == MozLangGroups[i].mozLangGroup) {
- mozLangGroup = &MozLangGroups[i];
- break;
- }
- }
-
- // -- not a mozilla lang group? Just return the BCP47 string
- // representation of the lang group
- if (!mozLangGroup) {
- // Not a special mozilla language group.
- // Use aLanguage as a language code.
- aLanguage->ToUTF8String(aLangStr);
- return;
- }
-
- // -- check the environment for the user's preferred language that
- // corresponds to this mozilla lang group.
- const char *languages = getenv("LANGUAGE");
- if (languages) {
- const char separator = ':';
-
- for (const char *pos = languages; true; ++pos) {
- if (*pos == '\0' || *pos == separator) {
- if (languages < pos &&
- TryLangForGroup(Substring(languages, pos),
- aLanguage, aLangStr))
- return;
-
- if (*pos == '\0')
- break;
-
- languages = pos + 1;
- }
- }
- }
- const char *ctype = setlocale(LC_CTYPE, nullptr);
- if (ctype &&
- TryLangForGroup(nsDependentCString(ctype), aLanguage, aLangStr)) {
- return;
- }
-
- if (mozLangGroup->defaultLang) {
- aLangStr.Assign(mozLangGroup->defaultLang);
- } else {
- aLangStr.Truncate();
- }
-}
-
gfxFontconfigFontEntry::gfxFontconfigFontEntry(const nsAString& aFaceName,
FcPattern* aFontPattern)
: gfxFontEntry(aFaceName), mFontPattern(aFontPattern),
diff --git a/gfx/thebes/gfxFcPlatformFontList.h b/gfx/thebes/gfxFcPlatformFontList.h
index 6cedc9bd4e..8873a59093 100644
--- a/gfx/thebes/gfxFcPlatformFontList.h
+++ b/gfx/thebes/gfxFcPlatformFontList.h
@@ -245,8 +245,6 @@ public:
mGenericMappings.Clear();
}
- void GetSampleLangForGroup(nsIAtom* aLanguage, nsACString& aLangStr);
-
static FT_Library GetFTLibrary();
protected:
@@ -263,10 +261,6 @@ protected:
// are all pref font settings set to use fontconfig generics?
bool PrefFontListsUseOnlyGenerics();
- // helper method for finding an appropriate fontconfig language
- bool TryLangForGroup(const nsACString& aOSLang, nsIAtom* aLangGroup,
- nsACString& aFcLang);
-
static void CheckFontUpdates(nsITimer *aTimer, void *aThis);
#ifdef MOZ_BUNDLED_FONTS
diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp
index 44f51d6a42..2ba4522b96 100644
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -1943,7 +1943,8 @@ gfxFont::DrawEmphasisMarks(gfxTextRun* aShapedText, gfxPoint* aPt,
const EmphasisMarkDrawParams& aParams)
{
gfxFloat& inlineCoord = aParams.isVertical ? aPt->y : aPt->x;
- uint32_t markLength = aParams.mark->GetLength();
+ gfxTextRun::Range markRange(aParams.mark);
+ gfxTextRun::DrawParams params(aParams.context);
gfxFloat clusterStart = -std::numeric_limits::infinity();
bool shouldDrawEmphasisMark = false;
@@ -1965,8 +1966,7 @@ gfxFont::DrawEmphasisMarks(gfxTextRun* aShapedText, gfxPoint* aPt,
// Move the coord backward to get the needed start point.
gfxFloat delta = (clusterAdvance + aParams.advance) / 2;
inlineCoord -= delta;
- aParams.mark->Draw(aParams.context, *aPt, DrawMode::GLYPH_FILL,
- 0, markLength, nullptr, nullptr, nullptr);
+ aParams.mark->Draw(markRange, *aPt, params);
inlineCoord += delta;
shouldDrawEmphasisMark = false;
}
@@ -3198,7 +3198,8 @@ gfxFont::InitFakeSmallCapsRun(DrawTarget *aDrawTarget,
MergeCharactersInTextRun(mergedRun, tempRun,
charsToMergeArray.Elements(),
deletedCharsArray.Elements());
- aTextRun->CopyGlyphDataFrom(mergedRun, 0, runLength,
+ gfxTextRun::Range runRange(0, runLength);
+ aTextRun->CopyGlyphDataFrom(mergedRun, runRange,
aOffset + runStart);
}
} else {
diff --git a/gfx/thebes/gfxFontUtils.cpp b/gfx/thebes/gfxFontUtils.cpp
index 6b7b0ef9fb..af7b896a10 100644
--- a/gfx/thebes/gfxFontUtils.cpp
+++ b/gfx/thebes/gfxFontUtils.cpp
@@ -388,7 +388,7 @@ gfxFontUtils::ReadCMAPTableFormat14(const uint8_t *aBuf, uint32_t aLength,
#define acceptableUCS4Encoding(p, e, k) \
(((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDUCS4ForMicrosoftPlatform) && (k) != 12 || \
((p) == PLATFORM_ID_UNICODE && \
- ((e) == EncodingIDDefaultForUnicodePlatform || (e) >= EncodingIDUCS4ForUnicodePlatform)))
+ ((e) != EncodingIDUVSForUnicodePlatform)))
#else
#define acceptableFormat4(p,e,k) ((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDMicrosoft)
@@ -960,19 +960,19 @@ gfxFontUtils::DetermineFontDataType(const uint8_t *aFontData, uint32_t aFontData
return GFX_USERFONT_UNKNOWN;
}
-/* static */
-TableDirEntry*
-gfxFontUtils::FindTableDirEntry(const void* aFontData, uint32_t aTableTag)
-{
- const SFNTHeader* header =
- reinterpret_cast(aFontData);
- const TableDirEntry* dir =
- reinterpret_cast(header + 1);
- return static_cast
- (bsearch(&aTableTag, dir, uint16_t(header->numTables),
- sizeof(TableDirEntry), DirEntryCmp));
-}
-
+/* static */
+TableDirEntry*
+gfxFontUtils::FindTableDirEntry(const void* aFontData, uint32_t aTableTag)
+{
+ const SFNTHeader* header =
+ reinterpret_cast(aFontData);
+ const TableDirEntry* dir =
+ reinterpret_cast(header + 1);
+ return static_cast
+ (bsearch(&aTableTag, dir, uint16_t(header->numTables),
+ sizeof(TableDirEntry), DirEntryCmp));
+}
+
nsresult
gfxFontUtils::RenameFont(const nsAString& aName, const uint8_t *aFontData,
@@ -1057,9 +1057,9 @@ gfxFontUtils::RenameFont(const nsAString& aName, const uint8_t *aFontData,
SFNTHeader *sfntHeader = reinterpret_cast(newFontData);
// table directory entries begin immediately following SFNT header
- TableDirEntry *dirEntry =
- FindTableDirEntry(newFontData, TRUETYPE_TAG('n','a','m','e'));
- // function only called if font validates, so this should always be true
+ TableDirEntry *dirEntry =
+ FindTableDirEntry(newFontData, TRUETYPE_TAG('n','a','m','e'));
+ // function only called if font validates, so this should always be true
MOZ_ASSERT(dirEntry, "attempt to rename font with no name table");
uint32_t numTables = sfntHeader->numTables;
diff --git a/gfx/thebes/gfxFontUtils.h b/gfx/thebes/gfxFontUtils.h
index bbda813660..816a570150 100644
--- a/gfx/thebes/gfxFontUtils.h
+++ b/gfx/thebes/gfxFontUtils.h
@@ -98,7 +98,6 @@ public:
bool hasBlocksInRange = false;
endBlock = aEnd >> BLOCK_INDEX_SHIFT;
- blockIndex = startBlock;
for (blockIndex = startBlock; blockIndex <= endBlock; blockIndex++) {
if (blockIndex < blockLen && mBlocks[blockIndex])
hasBlocksInRange = true;
@@ -856,18 +855,18 @@ public:
GetFamilyNameFromTable(hb_blob_t *aNameTable,
nsAString& aFamilyName);
- // Find the table directory entry for a given table tag, in a (validated)
- // buffer of 'sfnt' data. Returns null if the tag is not present.
- static mozilla::TableDirEntry*
- FindTableDirEntry(const void* aFontData, uint32_t aTableTag);
-
- // Return a blob that wraps a table found within a buffer of font data.
- // The blob does NOT own its data; caller guarantees that the buffer
- // will remain valid at least as long as the blob.
- // Returns null if the specified table is not found.
- // This method assumes aFontData is valid 'sfnt' data; before using this,
- // caller is responsible to do any sanitization/validation necessary.
- static hb_blob_t*
+ // Find the table directory entry for a given table tag, in a (validated)
+ // buffer of 'sfnt' data. Returns null if the tag is not present.
+ static mozilla::TableDirEntry*
+ FindTableDirEntry(const void* aFontData, uint32_t aTableTag);
+
+ // Return a blob that wraps a table found within a buffer of font data.
+ // The blob does NOT own its data; caller guarantees that the buffer
+ // will remain valid at least as long as the blob.
+ // Returns null if the specified table is not found.
+ // This method assumes aFontData is valid 'sfnt' data; before using this,
+ // caller is responsible to do any sanitization/validation necessary.
+ static hb_blob_t*
GetTableFromFontData(const void* aFontData, uint32_t aTableTag);
// create a new name table and build a new font with that name table
diff --git a/gfx/thebes/gfxFontconfigFonts.cpp b/gfx/thebes/gfxFontconfigFonts.cpp
index 2ccb6897f4..acd77318e6 100644
--- a/gfx/thebes/gfxFontconfigFonts.cpp
+++ b/gfx/thebes/gfxFontconfigFonts.cpp
@@ -1625,9 +1625,14 @@ gfxPangoFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh,
nextFont = 1;
}
- // Pango, GLib, and Thebes (but not harfbuzz!) all happen to use the same
- // script codes, so we can just cast the value here.
- const PangoScript script = static_cast(aRunScript);
+ // Our MOZ_SCRIPT_* codes may not match the PangoScript enumeration values
+ // (if we're using ICU's codes), so convert by mapping through ISO 15924 tag.
+ // Note that PangoScript is defined to be compatible with GUnicodeScript:
+ // https://developer.gnome.org/pango/stable/pango-Scripts-and-Languages.html#PangoScript
+ const hb_tag_t scriptTag = GetScriptTagForCode(aRunScript);
+ const PangoScript script =
+ (const PangoScript)g_unicode_script_from_iso15924(scriptTag);
+
// Might be nice to call pango_language_includes_script only once for the
// run rather than for each character.
PangoLanguage *scriptLang;
@@ -1654,19 +1659,6 @@ gfxPangoFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh,
return nullptr;
}
-// Sanity-check: spot-check a few constants to confirm that Thebes and
-// Pango script codes really do match
-#define CHECK_SCRIPT_CODE(script) \
- PR_STATIC_ASSERT(int32_t(MOZ_SCRIPT_##script) == \
- int32_t(PANGO_SCRIPT_##script))
-
-CHECK_SCRIPT_CODE(COMMON);
-CHECK_SCRIPT_CODE(INHERITED);
-CHECK_SCRIPT_CODE(ARABIC);
-CHECK_SCRIPT_CODE(LATIN);
-CHECK_SCRIPT_CODE(UNKNOWN);
-CHECK_SCRIPT_CODE(NKO);
-
/**
** gfxFcFont
**/
diff --git a/gfx/thebes/gfxHarfBuzzShaper.cpp b/gfx/thebes/gfxHarfBuzzShaper.cpp
index a8307543ba..3fd195c2f2 100644
--- a/gfx/thebes/gfxHarfBuzzShaper.cpp
+++ b/gfx/thebes/gfxHarfBuzzShaper.cpp
@@ -354,17 +354,6 @@ gfxHarfBuzzShaper::HBGetGlyphVAdvance(hb_font_t *font, void *font_data,
return fcd->mShaper->GetGlyphVAdvance(glyph);
}
-/* static */
-hb_bool_t
-gfxHarfBuzzShaper::HBGetGlyphHOrigin(hb_font_t *font, void *font_data,
- hb_codepoint_t glyph,
- hb_position_t *x, hb_position_t *y,
- void *user_data)
-{
- // We work in horizontal coordinates, so no origin adjustment needed here.
- return true;
-}
-
struct VORG {
AutoSwap_PRUint16 majorVersion;
AutoSwap_PRUint16 minorVersion;
@@ -1267,9 +1256,6 @@ gfxHarfBuzzShaper::Initialize()
hb_font_funcs_set_glyph_v_advance_func(sHBFontFuncs,
HBGetGlyphVAdvance,
nullptr, nullptr);
- hb_font_funcs_set_glyph_h_origin_func(sHBFontFuncs,
- HBGetGlyphHOrigin,
- nullptr, nullptr);
hb_font_funcs_set_glyph_v_origin_func(sHBFontFuncs,
HBGetGlyphVOrigin,
nullptr, nullptr);
diff --git a/gfx/thebes/gfxHarfBuzzShaper.h b/gfx/thebes/gfxHarfBuzzShaper.h
index 122dec4a34..7171171562 100644
--- a/gfx/thebes/gfxHarfBuzzShaper.h
+++ b/gfx/thebes/gfxHarfBuzzShaper.h
@@ -61,11 +61,6 @@ public:
hb_codepoint_t glyph, void *user_data);
static hb_bool_t
- HBGetGlyphHOrigin(hb_font_t *font, void *font_data,
- hb_codepoint_t glyph,
- hb_position_t *x, hb_position_t *y,
- void *user_data);
- static hb_bool_t
HBGetGlyphVOrigin(hb_font_t *font, void *font_data,
hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y,
diff --git a/gfx/thebes/gfxMacPlatformFontList.h b/gfx/thebes/gfxMacPlatformFontList.h
index 766a4c08e4..7a09542c74 100644
--- a/gfx/thebes/gfxMacPlatformFontList.h
+++ b/gfx/thebes/gfxMacPlatformFontList.h
@@ -6,7 +6,11 @@
#ifndef gfxMacPlatformFontList_H_
#define gfxMacPlatformFontList_H_
+#include
#include
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5)
+#include
+#endif
#include "mozilla/MemoryReporting.h"
#include "nsDataHashtable.h"
@@ -32,13 +36,34 @@ public:
bool aIsStandardFace = false);
// for use with data fonts
+#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
MacOSFontEntry(const nsAString& aPostscriptName, CGFontRef aFontRef,
+#else
+ MacOSFontEntry(const nsAString& aPostscriptName, ATSFontRef aFontRef,
+#endif
uint16_t aWeight, uint16_t aStretch, uint8_t aStyle,
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5)
+ ATSFontContainerRef aContainerRef, // 10.4Fx
+#endif
bool aIsDataUserFont, bool aIsLocal);
virtual ~MacOSFontEntry() {
+#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
::CGFontRelease(mFontRef);
+#else
+ if (mFontRefInitialized)
+ ::CGFontRelease(mFontRef);
+ /* Per Apple, even synthesized CGFontRefs must be released. Also,
+ we do need to release our container ref, if any. */
+ if (mContainerRef)
+ ::ATSFontDeactivate(mContainerRef, NULL,
+ kATSOptionFlagsDefault);
+#endif
}
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5)
+ // 10.4Fx
+ ATSFontRef GetATSFontRef();
+#endif
virtual CGFontRef GetFontRef();
@@ -63,7 +88,15 @@ protected:
static void DestroyBlobFunc(void* aUserData);
CGFontRef mFontRef; // owning reference to the CGFont, released on destruction
-
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5)
+ // 10.4Fx class variables
+ ATSFontRef mATSFontRef; // 10.4Fx (owning reference to our ATSFont)
+ ATSFontContainerRef mContainerRef; // 10.4Fx (for MakePlatformFont)
+ bool mATSFontRefInitialized; // 10.4Fx. mUserFontData is in gfxFont.h.
+ AutoTArray mFontTableDir; // 10.4Fx
+ ByteCount mFontTableDirSize; // 10.4Fx
+ void TryGlobalFontTableCache();
+#endif
bool mFontRefInitialized;
bool mRequiresAAT;
bool mIsCFF;
@@ -124,11 +157,21 @@ private:
// helper function to lookup in both hidden system fonts and normal fonts
gfxFontFamily* FindSystemFontFamily(const nsAString& aFamily);
+#if defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
static void RegisteredFontsChangedNotificationCallback(CFNotificationCenterRef center,
void *observer,
CFStringRef name,
const void *object,
CFDictionaryRef userInfo);
+#else
+ // eliminate faces which have the same ATS font reference
+ // backout bug 663688
+ void EliminateDuplicateFaces(const nsAString& aFamilyName);
+
+ // backout bug 869762
+ static void ATSNotification(ATSFontNotificationInfoRef aInfo, void* aUserArg);
+ uint32_t mATSGeneration;
+#endif
// search fonts system-wide for a given character, null otherwise
gfxFontEntry* GlobalFontFallback(const uint32_t aCh,
diff --git a/gfx/thebes/gfxMacPlatformFontList.mm b/gfx/thebes/gfxMacPlatformFontList.mm
index 75fe3efeed..573eb6c892 100644
--- a/gfx/thebes/gfxMacPlatformFontList.mm
+++ b/gfx/thebes/gfxMacPlatformFontList.mm
@@ -69,6 +69,7 @@
#include
#include
+#include
using namespace mozilla;
@@ -278,14 +279,27 @@ MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName,
mRequiresAAT(false),
mIsCFF(false),
mIsCFFInitialized(false)
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5)
+ , mATSFontRef(kInvalidFont),
+ mFontTableDirSize(0),
+ mContainerRef(NULL),
+ mATSFontRefInitialized(false) /* 10.4Fx */
+#endif // 10.5
{
mWeight = aWeight;
}
MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName,
+#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
CGFontRef aFontRef,
+#else
+ ATSFontRef aFontRef, // 10.4Fx
+#endif
uint16_t aWeight, uint16_t aStretch,
uint8_t aStyle,
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5)
+ ATSFontContainerRef aContainerRef, // 10.4Fx
+#endif
bool aIsDataUserFont,
bool aIsLocalUserFont)
: gfxFontEntry(aPostscriptName, false),
@@ -295,9 +309,18 @@ MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName,
mIsCFF(false),
mIsCFFInitialized(false)
{
+#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
mFontRef = aFontRef;
mFontRefInitialized = true;
::CFRetain(mFontRef);
+#else
+ // ATSFontRef version
+ // We don't retain mFontRef here because we synthesize it.
+ mATSFontRef = aFontRef;
+ mATSFontRefInitialized = true; // keep mFontRef as if not initialized
+ mContainerRef = aContainerRef;
+ mFontTableDirSize = 0;
+#endif
mWeight = aWeight;
mStretch = aStretch;
@@ -310,6 +333,7 @@ MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName,
mIsLocalUserFont = aIsLocalUserFont;
}
+#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
CGFontRef
MacOSFontEntry::GetFontRef()
{
@@ -320,6 +344,39 @@ MacOSFontEntry::GetFontRef()
}
return mFontRef;
}
+#else
+/* Define ATSFontRef and CGFontRef getters for 10.4/5. */
+ATSFontRef
+MacOSFontEntry::GetATSFontRef()
+{
+ if (!mATSFontRefInitialized) {
+ mATSFontRefInitialized = true;
+ NSString *psname = GetNSStringForString(mName);
+ mATSFontRef = ::ATSFontFindFromPostScriptName(CFStringRef(psname),
+ kATSOptionFlagsDefault);
+ }
+ return mATSFontRef;
+}
+CGFontRef
+MacOSFontEntry::GetFontRef()
+{
+ if (mFontRefInitialized) {
+ return mFontRef;
+ }
+
+ // GetATSFontRef will initialize mATSFontRef
+ if (GetATSFontRef() == kInvalidFont) {
+ return nullptr;
+ }
+
+ mFontRef = ::CGFontCreateWithPlatformFont(&mATSFontRef);
+ // Per Apple, we need to release this later with CGFontRelease. See
+// https://developer.apple.com/library/mac/documentation/graphicsimaging/reference/CGFont/DeprecationAppendix/AppendixADeprecatedAPI.html
+ mFontRefInitialized = true;
+
+ return mFontRef;
+}
+#endif // 10.6 and up
// For a logging build, we wrap the CFDataRef in a FontTableRec so that we can
// use the MOZ_COUNT_[CD]TOR macros in it. A release build without logging
@@ -352,9 +409,34 @@ MacOSFontEntry::DestroyBlobFunc(void* aUserData)
#endif
}
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5)
+// It is possible for multiple entries to be instantiated that have no clue
+// of each other, making us reload this font multiple times (usually kicked
+// off by gfxTextRun). Accelerating webfonts is generally pointless, but for
+// platform fonts, we can cache the directory globally in the platform
+// object and save substantial time.
+void
+MacOSFontEntry::TryGlobalFontTableCache()
+{
+ if (mFontTableDirSize) return;
+
+ ByteCount trys = reinterpret_cast(
+ gfxPlatform::GetPlatform())->GetCachedDirSizeForFont(mName);
+ if (!trys) return;
+ uint8_t *x = reinterpret_cast(
+ gfxPlatform::GetPlatform())->GetCachedDirForFont(mName);
+ if (!x) return;
+ mFontTableDirSize = trys;
+ mFontTableDir.SetLength(trys, fallible);
+ memcpy(mFontTableDir.Elements(), x, trys);
+ return;
+}
+#endif
+
hb_blob_t *
MacOSFontEntry::GetFontTable(uint32_t aTag)
{
+#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
CGFontRef fontRef = GetFontRef();
if (!fontRef) {
return nullptr;
@@ -374,11 +456,139 @@ MacOSFontEntry::GetFontTable(uint32_t aTag)
}
return nullptr;
+#else // 10.5
+ // ATSFontRef version
+ // This is based on the high probability we called HasFontTable() before
+ // we called this to actually get it; HasFontTable() will cache the
+ // directory for us.
+ nsAutoreleasePool localPool;
+
+ ATSFontRef fontRef = GetATSFontRef();
+ if (fontRef == kInvalidFont) return nullptr;
+
+ ByteCount dataLength = 0;
+
+ if (!mIsDataUserFont || mIsLocalUserFont) TryGlobalFontTableCache();
+
+ // See if we already know how long the table is. This saves a potentially
+ // expensive call to ATSGetFontTable() to simply get the length.
+ // Essentially a hardcoded form of FindTagInTableDir; see below.
+ if (MOZ_LIKELY(mFontTableDirSize > 0)) {
+ uint32_t aTagHE = aTag;
+#ifndef __ppc__
+ aTagHE = __builtin_bswap32(aTag);
+#endif
+
+#ifdef DEBUG_X
+ uint32_t j = 12;
+ uint8_t *table = (reinterpret_cast(
+ mFontTableDir.Elements()));
+ fprintf(stderr, "fast fetch ");
+#endif
+ uint32_t i;
+ uint32_t *wtable = (reinterpret_cast(
+ mFontTableDir.Elements()));
+
+ for (i=3; i<(mFontTableDirSize/4); i+=4) { // Skip header
+#ifdef DEBUG_X
+ char tag[5] = { table[j], table[j+1], table[j+2], table[j+3],
+ '\0' };
+ fprintf(stderr, "%s ", tag); // remember: host endian
+ j += 16;
+#endif
+ // ASSUME THAT aTag is in host endianness
+ if(wtable[i] == aTagHE) {
+ dataLength = (ByteCount)wtable[i+3];
+#ifndef __ppc__
+ dataLength = __builtin_bswap32(dataLength);
+#endif
+#ifdef DEBUG_X
+ fprintf(stderr, "FF MATCH: length %u\n", dataLength);
+#endif
+ break;
+ }
+ }
+ }
+
+ if (MOZ_UNLIKELY(dataLength == 0)) {
+ // Either we don't know, or something was wrong with the table.
+#ifdef DEBUG_X
+ if (mFontTableDirSize > 0) fprintf(stderr, "NO MATCH\n");
+#endif
+ OSStatus status = ::ATSFontGetTable(fontRef, aTag, 0, 0, 0,
+ &dataLength);
+ if (MOZ_UNLIKELY(status != noErr)) return nullptr;
+ }
+
+ // Taking advantage of bridging CFMutableDataRef to CFDataRef.
+ CFMutableDataRef dataRef = ::CFDataCreateMutable(kCFAllocatorDefault,
+ dataLength);
+ if (!dataRef) return nullptr;
+
+ ::CFDataIncreaseLength(dataRef, dataLength); // paranoia
+ if(MOZ_UNLIKELY(::ATSFontGetTable(fontRef, aTag, 0, dataLength,
+ ::CFDataGetMutableBytePtr(dataRef),
+ &dataLength) != noErr)) {
+ ::CFRelease(dataRef);
+ return nullptr;
+ }
+
+ return hb_blob_create((const char*)::CFDataGetBytePtr(dataRef),
+ ::CFDataGetLength(dataRef),
+ HB_MEMORY_MODE_READONLY,
+#ifdef NS_BUILD_REFCNT_LOGGING
+ new FontTableRec(dataRef),
+#else
+ (void*)dataRef,
+#endif
+ DestroyBlobFunc);
+#endif // 10.6 and up
}
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5)
+static bool FindTagInTableDir(nsTArray& table,
+ uint32_t aTableTag, ByteCount sizer) {
+ // Parse it. In big endian format, each entry is 4 32-bit words
+ // corresponding to the tag, checksum, offset and length, with a
+ // 96 bit header (three 32-bit words). One day we could even write
+ // an AltiVec version ...
+ // aTableTag is expected to be Big Endian order
+#ifndef __ppc__
+ aTableTag = __builtin_bswap32(aTableTag);
+#endif
+
+#ifdef DEBUG_X
+ fprintf(stderr, "Tables: ");
+ uint32_t j = 12;
+#endif
+ uint32_t i;
+ uint32_t *wtable = (reinterpret_cast(table.Elements()));
+ for (i=3; i<(sizer/4); i+=4) { // Skip header
+#ifdef DEBUG_X
+ char tag[5] = { table[j], table[j+1], table[j+2], table[j+3], '\0' };
+ fprintf(stderr, "%s ", tag); // remember: big endian
+ j+=16;
+#endif
+ // ASSUME THAT aTableTag is already big endian (we converted it in case)
+ if(wtable[i] == aTableTag) {
+#ifdef DEBUG_X
+ fprintf(stderr, "MATCH\n");
+#endif
+ return true;
+ }
+ }
+ // Hmmm. Either something is wrong, or there is no table. So no table.
+#ifdef DEBUG_X
+ fprintf(stderr, "NO MATCH\n");
+#endif
+ return false;
+}
+#endif // 10.5
+
bool
MacOSFontEntry::HasFontTable(uint32_t aTableTag)
{
+#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
if (mAvailableTables.Count() == 0) {
nsAutoreleasePool localPool;
@@ -399,6 +609,53 @@ MacOSFontEntry::HasFontTable(uint32_t aTableTag)
}
return mAvailableTables.GetEntry(aTableTag);
+#else
+ // ATSFontRef version
+ // This is higher performance than the previous version.
+
+ ATSFontRef fontRef = GetATSFontRef();
+ if (fontRef == kInvalidFont) return false;
+
+ if (!mIsDataUserFont || mIsLocalUserFont) TryGlobalFontTableCache();
+
+ // Use cached directory to avoid repeatedly fetching the same data.
+ if (MOZ_LIKELY(mFontTableDirSize > 0))
+ return FindTagInTableDir(mFontTableDir, aTableTag, mFontTableDirSize);
+
+ ByteCount sizer;
+
+ if(MOZ_LIKELY(::ATSFontGetTableDirectory(fontRef, 0, NULL, &sizer) == noErr)) {
+ // If the header is abnormal, try the old, slower way in case this
+ // is a gap in our algorithm.
+ if (MOZ_UNLIKELY(sizer <= 12 || ((sizer-12) % 16) || sizer >= 1024)) {
+ fprintf(stderr, "Warning: TenFourFox found "
+ "abnormal font table dir in %s (%i).\n",
+ NS_ConvertUTF16toUTF8(mName).get(), sizer);
+ return
+ (::ATSFontGetTable(fontRef, aTableTag, 0, 0, 0, &sizer) == noErr);
+ }
+
+ // Get and cache the font table directory.
+ mFontTableDirSize = sizer;
+ mFontTableDir.SetLength(mFontTableDirSize, fallible);
+
+#ifdef DEBUG
+ fprintf(stderr, "Size of %s font table directory: %i\n",
+ NS_ConvertUTF16toUTF8(mName).get(), mFontTableDir.Length());
+#endif
+ if (MOZ_LIKELY(::ATSFontGetTableDirectory(fontRef, mFontTableDirSize,
+ reinterpret_cast(mFontTableDir.Elements()), &sizer) == noErr)) {
+
+ // Push to platform.
+ if (!mIsDataUserFont || mIsLocalUserFont)
+ reinterpret_cast(gfxPlatform::GetPlatform())->SetCachedDirForFont(mName, reinterpret_cast(mFontTableDir.Elements()), mFontTableDirSize);
+
+ return FindTagInTableDir(mFontTableDir, aTableTag, mFontTableDirSize);
+ }
+ }
+ mFontTableDirSize = 0;
+ return nullptr;
+#endif // 10.6 and up
}
void
@@ -424,6 +681,11 @@ public:
virtual void LocalizedName(nsAString& aLocalizedName);
virtual void FindStyleVariations(FontInfoData *aFontInfoData = nullptr);
+
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5)
+
+ void EliminateDuplicateFaces(); // needed for 10.4
+#endif
};
void
@@ -569,6 +831,58 @@ gfxMacFontFamily::FindStyleVariations(FontInfoData *aFontInfoData)
}
}
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5)
+// restored from bug 663688 for 10.4
+void
+gfxMacFontFamily::EliminateDuplicateFaces()
+{
+ uint32_t i, bold, numFonts, italicIndex;
+ MacOSFontEntry *italic, *nonitalic;
+
+ FindStyleVariations();
+
+ // if normal and italic have the same ATS font ref, delete italic
+ // if bold and bold-italic have the same ATS font ref, delete bold-italic
+
+ // two iterations, one for normal, one for bold
+ for (bold = 0; bold < 2; bold++) {
+ numFonts = mAvailableFonts.Length();
+
+ // find the non-italic face
+ nonitalic = nullptr;
+ for (i = 0; i < numFonts; i++) {
+ if ((mAvailableFonts[i]->IsBold() == (bold == 1)) &&
+ !mAvailableFonts[i]->IsItalic()) {
+ nonitalic = static_cast(mAvailableFonts[i].get());
+ break;
+ }
+ }
+
+ // find the italic face
+ if (nonitalic) {
+ italic = nullptr;
+ for (i = 0; i < numFonts; i++) {
+ if ((mAvailableFonts[i]->IsBold() == (bold == 1)) &&
+ mAvailableFonts[i]->IsItalic()) {
+ italic = static_cast(mAvailableFonts[i].get());
+ italicIndex = i;
+ break;
+ }
+ }
+
+ // if italic face and non-italic face have matching ATS refs,
+ // or if the italic returns 0 rather than an actual ATSFontRef,
+ // then the italic face is bogus so remove it
+ if (italic && (italic->GetATSFontRef() == 0 ||
+ italic->GetATSFontRef() == kInvalidFont ||
+ italic->GetATSFontRef() == nonitalic->GetATSFontRef())) {
+ mAvailableFonts.RemoveElementAt(italicIndex);
+ }
+ }
+ }
+}
+#endif // 10.5 only
+
/* gfxSingleFaceMacFontFamily */
#pragma mark-
@@ -645,19 +959,31 @@ gfxSingleFaceMacFontFamily::ReadOtherFamilyNames(gfxPlatformFontList *aPlatformF
gfxMacPlatformFontList::gfxMacPlatformFontList() :
gfxPlatformFontList(false),
+#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
mDefaultFont(nullptr),
+#else
+ mDefaultFont(NULL), // we can't use nullptr for an ATSFontRef
+ mATSGeneration(uint32_t(kATSGenerationInitial)), // backout bug 869762
+#endif
mUseSizeSensitiveSystemFont(false)
{
#ifdef MOZ_BUNDLED_FONTS
ActivateBundledFonts();
#endif
+#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
::CFNotificationCenterAddObserver(::CFNotificationCenterGetLocalCenter(),
this,
RegisteredFontsChangedNotificationCallback,
kCTFontManagerRegisteredFontsChangedNotification,
0,
CFNotificationSuspensionBehaviorDeliverImmediately);
+#else
+ // backout bug 869762
+ ::ATSFontNotificationSubscribe(ATSNotification,
+ kATSFontNotifyOptionDefault,
+ (void*)this, nullptr);
+#endif // 10.6 and up
// cache this in a static variable so that MacOSFontFamily objects
// don't have to repeatedly look it up
@@ -678,9 +1004,11 @@ gfxMacPlatformFontList::gfxMacPlatformFontList() :
gfxMacPlatformFontList::~gfxMacPlatformFontList()
{
+#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
if (mDefaultFont) {
::CFRelease(mDefaultFont);
}
+#endif // 10.6 and up
}
void
@@ -714,6 +1042,8 @@ gfxMacPlatformFontList::AddFamily(CFStringRef aFamily)
}
}
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5)
+#endif
nsresult
gfxMacPlatformFontList::InitFontList()
{
@@ -721,10 +1051,21 @@ gfxMacPlatformFontList::InitFontList()
Telemetry::AutoTimer timer;
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5)
+// backout bug 869762
+ ATSGeneration currentGeneration = ::ATSGetGeneration();
+
+ // need to ignore notifications after adding each font
+ if (mATSGeneration == currentGeneration)
+ return NS_OK;
+ mATSGeneration = currentGeneration;
+#endif
+
// reset font lists
gfxPlatformFontList::InitFontList();
mSystemFontFamilies.Clear();
+#if defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
// iterate over available families
CFArrayRef familyNames = CTFontManagerCopyAvailableFontFamilyNames();
@@ -734,6 +1075,32 @@ gfxMacPlatformFontList::InitFontList()
}
CFRelease(familyNames);
+#else
+ // Pre-Core Text version.
+ // XXX Currently we don't populate mSystemFontFamilies.
+
+ NSEnumerator *families = [[sFontManager availableFontFamilies]
+ objectEnumerator];
+ // returns "canonical", non-localized family name
+
+ nsAutoString availableFamilyName;
+ NSString *availableFamily = nil;
+ while ((availableFamily = [families nextObject])) {
+ // make a nsString
+ nsCocoaUtils::GetStringForNSString(availableFamily, availableFamilyName);
+ // create a family entry
+ gfxFontFamily *familyEntry = new gfxMacFontFamily(availableFamilyName);
+ if (!familyEntry) break;
+
+ // add the family entry to the hash table
+ ToLowerCase(availableFamilyName);
+ mFontFamilies.Put(availableFamilyName, familyEntry);
+
+ // check the bad underline blacklist
+ if (mBadUnderlineFamilyNames.Contains(availableFamilyName))
+ familyEntry->SetBadUnderlineFamily();
+ }
+#endif
InitSingleFaceList();
@@ -829,8 +1196,8 @@ gfxMacPlatformFontList::InitSystemFonts()
// display font family, if on OSX 10.11
if (mUseSizeSensitiveSystemFont) {
- sys = [NSFont systemFontOfSize: 128.0];
- NSString* displayFamilyName = GetRealFamilyName(sys);
+ NSFont* displaySys = [NSFont systemFontOfSize: 128.0];
+ NSString* displayFamilyName = GetRealFamilyName(displaySys);
nsCocoaUtils::GetStringForNSString(displayFamilyName, familyName);
mSystemDisplayFontFamily = FindSystemFontFamily(familyName);
NS_ASSERTION(mSystemDisplayFontFamily, "null system display font family");
@@ -848,7 +1215,6 @@ gfxMacPlatformFontList::InitSystemFonts()
"system text/display font size switch point is not as expected!");
#endif
}
-
}
gfxFontFamily*
@@ -884,6 +1250,7 @@ gfxMacPlatformFontList::GetStandardFamilyName(const nsAString& aFontName, nsAStr
return false;
}
+#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
void
gfxMacPlatformFontList::RegisteredFontsChangedNotificationCallback(CFNotificationCenterRef center,
void *observer,
@@ -903,6 +1270,21 @@ gfxMacPlatformFontList::RegisteredFontsChangedNotificationCallback(CFNotificatio
// modify a preference that will trigger reflow everywhere
fl->ForceGlobalReflow();
}
+#else
+// backout bug 869762
+void
+gfxMacPlatformFontList::ATSNotification(ATSFontNotificationInfoRef aInfo,
+ void* aUserArg)
+{
+ gfxMacPlatformFontList* fl = static_cast(aUserArg);
+
+ // xxx - should be carefully pruning the list of fonts, not rebuilding it from scratch
+ fl->UpdateFontList();
+
+ // modify a preference that will trigger reflow everywhere
+ fl->ForceGlobalReflow();
+}
+#endif
gfxFontEntry*
gfxMacPlatformFontList::GlobalFontFallback(const uint32_t aCh,
@@ -1033,6 +1415,28 @@ gfxMacPlatformFontList::LookupLocalFont(const nsAString& aFontName,
NSString *faceName = GetNSStringForString(aFontName);
MacOSFontEntry *newFontEntry;
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5)
+ // ATSFontRef version
+
+ // first lookup a single face based on postscript name
+ ATSFontRef fontRef = ::ATSFontFindFromPostScriptName(CFStringRef(faceName),
+ kATSOptionFlagsDefault);
+ // if not found, lookup using full font name
+ if (fontRef == kInvalidFont) {
+ fontRef = ::ATSFontFindFromName(CFStringRef(faceName),
+ kATSOptionFlagsDefault);
+ if (fontRef == kInvalidFont) {
+ return nullptr;
+ }
+ }
+
+ NS_ASSERTION(aWeight >= 100 && aWeight <= 900, "bogus font weight value!");
+
+ newFontEntry =
+ new MacOSFontEntry(aFontName, fontRef,
+ aWeight, aStretch,
+ aStyle, NULL, false, true); // we must use NULL
+#else
// lookup face based on postscript or full name
CGFontRef fontRef = ::CGFontCreateWithFontName(CFStringRef(faceName));
if (!fontRef) {
@@ -1046,6 +1450,7 @@ gfxMacPlatformFontList::LookupLocalFont(const nsAString& aFontName,
new MacOSFontEntry(aFontName, fontRef, aWeight, aStretch, aStyle,
false, true);
::CFRelease(fontRef);
+#endif
return newFontEntry;
}
@@ -1055,6 +1460,18 @@ static void ReleaseData(void *info, const void *data, size_t size)
NS_Free((void*)data);
}
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5)
+// Backout from bug 811312 (needed for MakePlatformFont)
+// grumble, another non-publised Apple API dependency (found in Webkit code)
+// activated with this value, font will not be found via system lookup routines
+// it can only be used via the created ATSFontRef
+// needed to prevent one doc from finding a font used in a separate doc
+
+enum {
+ kPrivateATSFontContextPrivate = 3
+};
+#endif
+
gfxFontEntry*
gfxMacPlatformFontList::MakePlatformFont(const nsAString& aFontName,
uint16_t aWeight,
@@ -1075,6 +1492,168 @@ gfxMacPlatformFontList::MakePlatformFont(const nsAString& aFontName,
return nullptr;
}
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5)
+ // ATSFontRef version
+ OSStatus err;
+
+ // MakePlatformFont is responsible for deleting the font data with NS_Free
+ // so we set up a stack object to ensure it is freed even if we take an
+ // early exit
+ // XXX Is this still needed? If we exit early, we die anyway.
+ struct FontDataDeleter {
+ FontDataDeleter(const uint8_t *aFontData)
+ : mFontData(aFontData) { }
+ ~FontDataDeleter() { NS_Free((void*)mFontData); }
+ const uint8_t *mFontData;
+ };
+ FontDataDeleter autoDelete(aFontData);
+
+ ATSFontRef fontRef;
+ ATSFontContainerRef containerRef;
+
+ // we get occasional failures when multiple fonts are activated in quick succession
+ // if the ATS font cache is damaged; to work around this, we can retry the activation
+ const uint32_t kMaxRetries = 3;
+ uint32_t retryCount = 0;
+ while (retryCount++ < kMaxRetries) {
+ err = ::ATSFontActivateFromMemory(const_cast(aFontData), aLength,
+ kPrivateATSFontContextPrivate,
+ kATSFontFormatUnspecified,
+ NULL,
+ kATSOptionFlagsDoNotNotify,
+ &containerRef);
+ mATSGeneration = ::ATSGetGeneration();
+
+ if (MOZ_UNLIKELY(err != noErr)) {
+#if DEBUG
+ char warnBuf[1024];
+ sprintf(warnBuf, "downloaded font error, ATSFontActivateFromMemory err: %d",
+ int32_t(err));
+ NS_WARNING(warnBuf);
+#endif
+ return nullptr;
+ }
+
+ // ignoring containers with multiple fonts, use the first face only for now
+ err = ::ATSFontFindFromContainer(containerRef, kATSOptionFlagsDefault, 1,
+ &fontRef, NULL);
+ if (MOZ_UNLIKELY(err != noErr)) {
+#if DEBUG
+ char warnBuf[1024];
+ sprintf(warnBuf, "downloaded font error, ATSFontFindFromContainer err: %d",
+ int32_t(err));
+ NS_WARNING(warnBuf);
+#endif
+ ::ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
+ return nullptr;
+ }
+
+ // now lookup the Postscript name; this may fail if the font cache is bad
+ OSStatus err;
+ NSString *psname = NULL;
+ err = ::ATSFontGetPostScriptName(fontRef, kATSOptionFlagsDefault, (CFStringRef*) (&psname));
+ if (MOZ_LIKELY(err == noErr)) {
+#if(0)
+ fprintf(stderr, "Trying: %s.\n", [psname UTF8String]);
+#endif
+ // Check the font blacklist (TenFourFox issue 261).
+ // Warning: fonts here do NOT properly fall back. Prefer URI blocking
+ // if we have the option.
+ if (0 ||
+ [psname isEqualToString:@"prisjakticons"] ||
+ [psname isEqualToString:@"FSEmericWeb-SemiBold"] ||
+ [psname isEqualToString:@"SFProText-Regular"] ||
+ [psname isEqualToString:@"SFProText-Bold"] ||
+ [psname isEqualToString:@"SFProText-Semibold"] ||
+ [psname isEqualToString:@"SFProDisplay-Medium"] ||
+ [psname isEqualToString:@"SFProDisplay-Light"] ||
+ [psname isEqualToString:@".SFNSDisplay-Ultralight"] ||
+ [psname isEqualToString:@".SFNSText-Light"] ||
+ [psname isEqualToString:@".SFNSDisplay-Light"] ||
+ [psname isEqualToString:@".SFNSText-Medium"] ||
+ [psname isEqualToString:@".SFNSDisplay-Medium"] ||
+ 0) {
+ fprintf(stderr,
+"Warning: TenFourFox rejected ATSUI-incompatible web font %s.\n",
+ [psname UTF8String]);
+ [psname release];
+ ::ATSFontDeactivate(containerRef, NULL,
+ kATSOptionFlagsDefault);
+
+ // Create a dummy font, since returning nullptr
+ // doesn't work properly anymore (TenFourFox issue
+ // 330).
+ MacOSFontEntry *newFontEntry =
+ new MacOSFontEntry(uniqueName,
+ NULL, // not nullptr
+ aWeight, aStretch, aStyle,
+ NULL, // not nullptr
+ true, false);
+ // Make it "valid with no characters."
+ newFontEntry->mIsValid = true;
+ newFontEntry->mCharacterMap = new gfxCharacterMap();
+ return newFontEntry;
+ }
+ [psname release];
+ } else {
+#ifdef DEBUG
+ char warnBuf[1024];
+ sprintf(warnBuf, "ATSFontGetPostScriptName err = %d, retries = %d",
+ (int32_t)err, retryCount);
+ NS_WARNING(warnBuf);
+#endif
+ ::ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
+ // retry the activation a couple of times if this fails
+ // (may be a transient failure due to ATS font cache issues)
+ continue;
+ }
+
+ // font entry will own the container ref now
+ // THIS MUST BE A C++ OBJECT, not an nsAutoPtr, or it will not
+ // live long enough to be instantiated!
+ MacOSFontEntry *newFontEntry =
+ new MacOSFontEntry(uniqueName,
+ fontRef,
+ aWeight,
+ aStretch,
+ aStyle,
+ containerRef, true, false);
+
+ // if succeeded and font cmap is good, return the new font
+ if (MOZ_LIKELY(newFontEntry->mIsValid && NS_SUCCEEDED(newFontEntry->ReadCMAP()))) {
+ return newFontEntry;
+ }
+
+ // if something is funky about this font, delete immediately
+#if DEBUG
+ char warnBuf[1024];
+ sprintf(warnBuf, "downloaded font not loaded properly, removed face");
+ NS_WARNING(warnBuf);
+#endif
+ delete newFontEntry;
+
+ // We don't retry from here; the ATS font cache issue would have caused failure earlier
+ // so if we get here, there's something else bad going on within our font data structures.
+ // Currently, there should be no way to reach here, as fontentry creation cannot fail
+ // except by memory allocation failure.
+ NS_WARNING("invalid font entry for a newly activated font");
+ break;
+ }
+
+ // If we get here, the activation failed (even with possible retries); we can't use this font.
+ // We can't just return nullptr anymore, so create a dummy font, like we do above.
+ fprintf(stderr, "Warning: TenFourFox detected ATSUI font failure; aborting font load.\n");
+ MacOSFontEntry *newFontEntry =
+ new MacOSFontEntry(uniqueName,
+ NULL, // not nullptr
+ aWeight, aStretch, aStyle,
+ NULL, // not nullptr
+ true, false);
+ // Make it "valid with no characters."
+ newFontEntry->mIsValid = true;
+ newFontEntry->mCharacterMap = new gfxCharacterMap();
+ return newFontEntry;
+#else
CGDataProviderRef provider =
::CGDataProviderCreateWithData(nullptr, aFontData, aLength,
&ReleaseData);
@@ -1102,6 +1681,7 @@ gfxMacPlatformFontList::MakePlatformFont(const nsAString& aFontName,
#endif
return nullptr;
+#endif
}
// Webkit code uses a system font meta name, so mimic that here
@@ -1219,6 +1799,7 @@ public:
virtual void LoadFontFamilyData(const nsAString& aFamilyName);
};
+#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
void
MacFontInfo::LoadFontFamilyData(const nsAString& aFamilyName)
{
@@ -1329,6 +1910,137 @@ MacFontInfo::LoadFontFamilyData(const nsAString& aFamilyName)
mLoadStats.othernames += otherFamilyNames.Length();
}
}
+#else
+// ATS-based version.
+void
+MacFontInfo::LoadFontFamilyData(const nsAString& aFamilyName)
+{
+ // ATS does not have the concept of fonts belonging to a family like
+ // CoreText does, but the list of names we got from [NSFontManager
+ // availableFontFamilies] may not exactly correspond to an ATS name.
+ // However, [NSFontManager availableMembersOfFontFamily] will tell us.
+
+NS_WARNING("LoadFontFamilyData not yet supported, do not call (bug 962440)");
+MOZ_ASSERT(0);
+
+#if(0)
+ nsAutoreleasePool bubble_bubble_toil_and_trouble;
+ NSString *famName = GetNSStringForString(aFamilyName);
+// CFStringRef family = CFStringRef(famName);
+ NSArray *matchingFonts =
+ [sFontManager availableMembersOfFontFamily:famName];
+ int f, numFaces = (int) CFArrayGetCount(matchingFonts);
+ if(!numFaces) {
+#ifdef DEBUG
+ fprintf(stderr, "no available fonts for family %s\n",
+ aFamilyName.get());
+#endif
+ return;
+ }
+
+ nsTArray otherFamilyNames;
+ bool hasOtherFamilyNames = true;
+
+ for (f = 0; f < numFaces; f++) {
+ mLoadStats.fonts++;
+
+ // Each element is an array of arrays:
+ // (("Times-Roman", "Roman", 5, 4), ...
+ // corresponding to the full PSName, the weight name, the weight
+ // and its traits. We only care about the PSName, because now we
+ // can get an ATSFontRef from that.
+ NSArray *k = (NSArray *)CFArrayGetValueAtIndex(matchingFonts, f);
+ if((int)CFArrayGetCount(k) < 2) { // wtf
+ continue;
+ }
+ NSString *psname = (NSString *)CFArrayGetValueAtIndex(k, 0);
+#ifdef DEBUG
+ fprintf(stderr, "Deferred loading: %s", [psname UTF8String]);
+#endif
+ ATSFontRef fontRef = ::ATSFontFindFromPostScriptName(
+ (CFStringRef)psname,
+ kATSOptionFlagsDefault);
+ if (!fontRef) { // wtff
+#ifdef DEBUG
+ fprintf(stderr, "Failed loading: %s", [psname UTF8String]);
+#endif
+ continue;
+ }
+
+ if (mLoadCmaps) {
+ // face name (fudge it into char16_t)
+ CFStringRef faceName = (CFStringRef)psname;
+ nsAutoTArray buffer;
+ CFIndex len = CFStringGetLength(faceName);
+ buffer.SetLength(len+1);
+ CFStringGetCharacters(faceName, ::CFRangeMake(0, len),
+ buffer.Elements());
+ buffer[len] = 0;
+ nsAutoString
+ fontName(reinterpret_cast(buffer.Elements()),
+ len);
+
+ // load the cmap data
+ FontFaceData fontData;
+
+// Replace with one of the ATSFontTable loaders, but this sucks.
+ //CFDataRef cmapTable = CTFontCopyTable(fontRef, kCTFontTableCmap,
+ // kCTFontTableOptionNoOptions);
+ if (cmapTable) {
+ bool unicodeFont = false, symbolFont = false; // ignored
+ const uint8_t *cmapData =
+ (const uint8_t*)CFDataGetBytePtr(cmapTable);
+ uint32_t cmapLen = CFDataGetLength(cmapTable);
+ RefPtr charmap = new gfxCharacterMap();
+ uint32_t offset;
+ nsresult rv;
+
+ rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen, *charmap, offset,
+ unicodeFont, symbolFont);
+ if (NS_SUCCEEDED(rv)) {
+ fontData.mCharacterMap = charmap;
+ fontData.mUVSOffset = offset;
+ fontData.mSymbolFont = symbolFont;
+ mLoadStats.cmaps++;
+ }
+ CFRelease(cmapTable);
+ }
+
+ mFontFaceData.Put(fontName, fontData);
+ CFRelease(faceName);
+ }
+
+#if (0)
+// I don't think this is true for ATS fonts.
+ if (mLoadOtherNames && hasOtherFamilyNames) {
+ CFDataRef nameTable = CTFontCopyTable(fontRef, kCTFontTableName,
+ kCTFontTableOptionNoOptions);
+ if (nameTable) {
+ const char *nameData = (const char*)CFDataGetBytePtr(nameTable);
+ uint32_t nameLen = CFDataGetLength(nameTable);
+ gfxFontFamily::ReadOtherFamilyNamesForFace(aFamilyName,
+ nameData, nameLen,
+ otherFamilyNames,
+ false);
+ hasOtherFamilyNames = otherFamilyNames.Length() != 0;
+ CFRelease(nameTable);
+ }
+ }
+
+ CFRelease(fontRef);
+ }
+#endif
+ CFRelease(matchingFonts);
+
+ // if found other names, insert them in the hash table
+ if (otherFamilyNames.Length() != 0) {
+ mOtherFamilyNames.Put(aFamilyName, otherFamilyNames);
+ mLoadStats.othernames += otherFamilyNames.Length();
+ }
+#endif
+}
+#endif // 10.6 and up
+
already_AddRefed
gfxMacPlatformFontList::CreateFontInfoData()
diff --git a/gfx/thebes/gfxPlatform.h b/gfx/thebes/gfxPlatform.h
index 916ab37e2b..362c24c4aa 100644
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -132,9 +132,15 @@ enum class DeviceResetReason
DRIVER_ERROR,
INVALID_CALL,
OUT_OF_MEMORY,
+ FORCED_RESET,
UNKNOWN
};
+enum class ForcedDeviceResetReason
+{
+ OPENSHAREDHANDLE = 0
+};
+
class gfxPlatform {
friend class SRGBOverrideObserver;
diff --git a/gfx/thebes/gfxPlatformFontList.cpp b/gfx/thebes/gfxPlatformFontList.cpp
index d9d9d94e4a..9ed85639bc 100644
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -25,6 +25,8 @@
#include "mozilla/TimeStamp.h"
#include "mozilla/gfx/2D.h"
+#include
+
using namespace mozilla;
#define LOG_FONTLIST(args) MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
@@ -1225,6 +1227,135 @@ gfxPlatformFontList::GetGenericName(FontFamilyType aGenericType)
return generic;
}
+// mapping of moz lang groups ==> default lang
+struct MozLangGroupData {
+ nsIAtom* const& mozLangGroup;
+ const char *defaultLang;
+};
+
+const MozLangGroupData MozLangGroups[] = {
+ { nsGkAtoms::x_western, "en" },
+ { nsGkAtoms::x_cyrillic, "ru" },
+ { nsGkAtoms::x_devanagari, "hi" },
+ { nsGkAtoms::x_tamil, "ta" },
+ { nsGkAtoms::x_armn, "hy" },
+ { nsGkAtoms::x_beng, "bn" },
+ { nsGkAtoms::x_cans, "iu" },
+ { nsGkAtoms::x_ethi, "am" },
+ { nsGkAtoms::x_geor, "ka" },
+ { nsGkAtoms::x_gujr, "gu" },
+ { nsGkAtoms::x_guru, "pa" },
+ { nsGkAtoms::x_khmr, "km" },
+ { nsGkAtoms::x_knda, "kn" },
+ { nsGkAtoms::x_mlym, "ml" },
+ { nsGkAtoms::x_orya, "or" },
+ { nsGkAtoms::x_sinh, "si" },
+ { nsGkAtoms::x_tamil, "ta" },
+ { nsGkAtoms::x_telu, "te" },
+ { nsGkAtoms::x_tibt, "bo" },
+ { nsGkAtoms::Unicode, 0 }
+};
+
+bool
+gfxPlatformFontList::TryLangForGroup(const nsACString& aOSLang,
+ nsIAtom* aLangGroup,
+ nsACString& aFcLang)
+{
+ // Truncate at '.' or '@' from aOSLang, and convert '_' to '-'.
+ // aOSLang is in the form "language[_territory][.codeset][@modifier]".
+ // fontconfig takes languages in the form "language-territory".
+ // nsILanguageAtomService takes languages in the form language-subtag,
+ // where subtag may be a territory. fontconfig and nsILanguageAtomService
+ // handle case-conversion for us.
+ const char *pos, *end;
+ aOSLang.BeginReading(pos);
+ aOSLang.EndReading(end);
+ aFcLang.Truncate();
+ while (pos < end) {
+ switch (*pos) {
+ case '.':
+ case '@':
+ end = pos;
+ break;
+ case '_':
+ aFcLang.Append('-');
+ break;
+ default:
+ aFcLang.Append(*pos);
+ }
+ ++pos;
+ }
+
+ nsILanguageAtomService* langService = GetLangService();
+ nsIAtom *atom = langService->LookupLanguage(aFcLang);
+ return atom == aLangGroup;
+}
+
+void
+gfxPlatformFontList::GetSampleLangForGroup(nsIAtom* aLanguage,
+ nsACString& aLangStr,
+ bool aCheckEnvironment)
+{
+ aLangStr.Truncate();
+ if (!aLanguage) {
+ return;
+ }
+
+ // set up lang string
+ const MozLangGroupData *mozLangGroup = nullptr;
+
+ // -- look it up in the list of moz lang groups
+ for (unsigned int i = 0; i < ArrayLength(MozLangGroups); ++i) {
+ if (aLanguage == MozLangGroups[i].mozLangGroup) {
+ mozLangGroup = &MozLangGroups[i];
+ break;
+ }
+ }
+
+ // -- not a mozilla lang group? Just return the BCP47 string
+ // representation of the lang group
+ if (!mozLangGroup) {
+ // Not a special mozilla language group.
+ // Use aLanguage as a language code.
+ aLanguage->ToUTF8String(aLangStr);
+ return;
+ }
+
+ // -- check the environment for the user's preferred language that
+ // corresponds to this mozilla lang group.
+ if (aCheckEnvironment) {
+ const char *languages = getenv("LANGUAGE");
+ if (languages) {
+ const char separator = ':';
+
+ for (const char *pos = languages; true; ++pos) {
+ if (*pos == '\0' || *pos == separator) {
+ if (languages < pos &&
+ TryLangForGroup(Substring(languages, pos),
+ aLanguage, aLangStr))
+ return;
+
+ if (*pos == '\0')
+ break;
+
+ languages = pos + 1;
+ }
+ }
+ }
+ const char *ctype = setlocale(LC_CTYPE, nullptr);
+ if (ctype &&
+ TryLangForGroup(nsDependentCString(ctype), aLanguage, aLangStr)) {
+ return;
+ }
+ }
+
+ if (mozLangGroup->defaultLang) {
+ aLangStr.Assign(mozLangGroup->defaultLang);
+ } else {
+ aLangStr.Truncate();
+ }
+}
+
void
gfxPlatformFontList::InitLoader()
{
diff --git a/gfx/thebes/gfxPlatformFontList.h b/gfx/thebes/gfxPlatformFontList.h
index 073c744303..394524eebf 100644
--- a/gfx/thebes/gfxPlatformFontList.h
+++ b/gfx/thebes/gfxPlatformFontList.h
@@ -237,6 +237,10 @@ public:
mozilla::FontFamilyType
GetDefaultGeneric(eFontPrefLang aLang);
+ // map lang group ==> lang string
+ void GetSampleLangForGroup(nsIAtom* aLanguage, nsACString& aLangStr,
+ bool aCheckEnvironment = true);
+
protected:
class MemoryReporter final : public nsIMemoryReporter
{
@@ -315,6 +319,10 @@ protected:
// helper function to map lang to lang group
nsIAtom* GetLangGroup(nsIAtom* aLanguage);
+ // helper method for finding an appropriate lang string
+ bool TryLangForGroup(const nsACString& aOSLang, nsIAtom* aLangGroup,
+ nsACString& aLang);
+
static const char* GetGenericName(mozilla::FontFamilyType aGenericType);
// gfxFontInfoLoader overrides, used to load in font cmaps
diff --git a/gfx/thebes/gfxPlatformMac.cpp b/gfx/thebes/gfxPlatformMac.cpp
index bc516e2ee8..f9ab0c6336 100644
--- a/gfx/thebes/gfxPlatformMac.cpp
+++ b/gfx/thebes/gfxPlatformMac.cpp
@@ -99,11 +99,38 @@ gfxPlatformMac::gfxPlatformMac()
MacIOSurfaceLib::LoadLibrary();
}
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5)
gfxPlatformMac::~gfxPlatformMac()
{
gfxCoreTextShaper::Shutdown();
}
+ByteCount
+gfxPlatformMac::GetCachedDirSizeForFont(nsString name)
+{
+ FontDirWrapper *x = PlatformFontDirCache.Get(name);
+ if (x) return x->sizer;
+ return 0;
+}
+uint8_t*
+gfxPlatformMac::GetCachedDirForFont(nsString name)
+{
+ FontDirWrapper *x = PlatformFontDirCache.Get(name);
+ if (x)
+ return x->fontDir;
+ else
+ return nullptr;
+}
+void
+gfxPlatformMac::SetCachedDirForFont(nsString name, uint8_t* table, ByteCount sizer)
+{
+ if (MOZ_UNLIKELY(sizer < 1 || sizer > 1023)) return;
+
+ FontDirWrapper *k = new FontDirWrapper(sizer, table);
+ PlatformFontDirCache.Put(name, k);
+}
+#endif
+
gfxPlatformFontList*
gfxPlatformMac::CreatePlatformFontList()
{
diff --git a/gfx/thebes/gfxPlatformMac.h b/gfx/thebes/gfxPlatformMac.h
index 0e45eefdb7..1c251e1412 100644
--- a/gfx/thebes/gfxPlatformMac.h
+++ b/gfx/thebes/gfxPlatformMac.h
@@ -6,10 +6,19 @@
#ifndef GFX_PLATFORM_MAC_H
#define GFX_PLATFORM_MAC_H
+#include
+
#include "nsTArrayForwardDeclare.h"
#include "gfxPlatform.h"
#include "mozilla/LookAndFeel.h"
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5)
+#include "nsDataHashtable.h"
+#include "nsClassHashtable.h"
+
+typedef size_t ByteCount;
+#endif
+
namespace mozilla {
namespace gfx {
class DrawTarget;
@@ -17,6 +26,21 @@ class VsyncSource;
} // namespace gfx
} // namespace mozilla
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5)
+// 10.4Fx
+class FontDirWrapper {
+public:
+ uint8_t fontDir[1024];
+ ByteCount sizer;
+ FontDirWrapper(ByteCount sized, uint8_t *dir) {
+ if (MOZ_UNLIKELY(sized < 1 || sized > 1023)) return;
+ sizer = sized;
+ memcpy(fontDir, dir, sizer);
+ }
+ ~FontDirWrapper() { }
+};
+#endif
+
class gfxPlatformMac : public gfxPlatform {
public:
gfxPlatformMac();
@@ -97,6 +121,13 @@ public:
// lower threshold on font anti-aliasing
uint32_t GetAntiAliasingThreshold() { return mFontAntiAliasingThreshold; }
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5)
+/* ATS acceleration functions for 10.4 */
+ByteCount GetCachedDirSizeForFont(nsString name);
+uint8_t *GetCachedDirForFont(nsString name);
+void SetCachedDirForFont(nsString name, uint8_t* table, ByteCount sizer);
+nsClassHashtable< nsStringHashKey, FontDirWrapper > PlatformFontDirCache;
+#endif
protected:
bool AccelerateLayersByDefault() override;
diff --git a/gfx/thebes/gfxScriptItemizer.cpp b/gfx/thebes/gfxScriptItemizer.cpp
index 3339503acd..b6091a0c3f 100644
--- a/gfx/thebes/gfxScriptItemizer.cpp
+++ b/gfx/thebes/gfxScriptItemizer.cpp
@@ -158,19 +158,11 @@ gfxScriptItemizer::Next(uint32_t& aRunStart, uint32_t& aRunLimit,
}
}
- // Get the nsCharProps2 record for the current character,
- // so we can read the script and (if needed) the gen category
- // without needing to do two multi-level lookups.
- // NOTE that this means we're relying on an implementation detail
- // of the nsUnicodeProperties tables, and might have to revise this
- // if the nsCharProps records used there are modified in future.
- const nsCharProps2& charProps = GetCharProps2(ch);
-
// Initialize gc to UNASSIGNED; we'll only set it to the true GC
// if the character has script=COMMON, otherwise we don't care.
uint8_t gc = HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
- sc = charProps.mScriptCode;
+ sc = GetScriptCode(ch);
if (sc == MOZ_SCRIPT_COMMON) {
/*
* Paired character handling:
@@ -183,7 +175,7 @@ gfxScriptItemizer::Next(uint32_t& aRunStart, uint32_t& aRunLimit,
* We only do this if the script is COMMON; for chars with
* specific script assignments, we just use them as-is.
*/
- gc = charProps.mCategory;
+ GetGeneralCategory(ch);
if (gc == HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION) {
uint32_t endPairChar = mozilla::unicode::GetMirroredChar(ch);
if (endPairChar != ch) {
diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp
index 694ffb2e9d..a2edd8f5dc 100644
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -210,15 +210,14 @@ gfxTextRun::ReleaseFontGroup()
}
bool
-gfxTextRun::SetPotentialLineBreaks(uint32_t aStart, uint32_t aLength,
- uint8_t *aBreakBefore)
+gfxTextRun::SetPotentialLineBreaks(Range aRange, uint8_t *aBreakBefore)
{
- NS_ASSERTION(aStart + aLength <= GetLength(), "Overflow");
+ NS_ASSERTION(aRange.end <= GetLength(), "Overflow");
uint32_t changed = 0;
uint32_t i;
- CompressedGlyph *charGlyphs = mCharacterGlyphs + aStart;
- for (i = 0; i < aLength; ++i) {
+ CompressedGlyph *charGlyphs = mCharacterGlyphs + aRange.start;
+ for (i = 0; i < aRange.Length(); ++i) {
uint8_t canBreak = aBreakBefore[i];
if (canBreak && !charGlyphs[i].IsClusterStart()) {
// This can happen ... there is no guarantee that our linebreaking rules
@@ -231,39 +230,39 @@ gfxTextRun::SetPotentialLineBreaks(uint32_t aStart, uint32_t aLength,
}
gfxTextRun::LigatureData
-gfxTextRun::ComputeLigatureData(uint32_t aPartStart, uint32_t aPartEnd,
- PropertyProvider *aProvider)
+gfxTextRun::ComputeLigatureData(Range aPartRange, PropertyProvider *aProvider)
{
- NS_ASSERTION(aPartStart < aPartEnd, "Computing ligature data for empty range");
- NS_ASSERTION(aPartEnd <= GetLength(), "Character length overflow");
+ NS_ASSERTION(aPartRange.start < aPartRange.end,
+ "Computing ligature data for empty range");
+ NS_ASSERTION(aPartRange.end <= GetLength(), "Character length overflow");
LigatureData result;
CompressedGlyph *charGlyphs = mCharacterGlyphs;
uint32_t i;
- for (i = aPartStart; !charGlyphs[i].IsLigatureGroupStart(); --i) {
+ for (i = aPartRange.start; !charGlyphs[i].IsLigatureGroupStart(); --i) {
NS_ASSERTION(i > 0, "Ligature at the start of the run??");
}
- result.mLigatureStart = i;
- for (i = aPartStart + 1; i < GetLength() && !charGlyphs[i].IsLigatureGroupStart(); ++i) {
+ result.mRange.start = i;
+ for (i = aPartRange.start + 1;
+ i < GetLength() && !charGlyphs[i].IsLigatureGroupStart(); ++i) {
}
- result.mLigatureEnd = i;
+ result.mRange.end = i;
- int32_t ligatureWidth =
- GetAdvanceForGlyphs(result.mLigatureStart, result.mLigatureEnd);
+ int32_t ligatureWidth = GetAdvanceForGlyphs(result.mRange);
// Count the number of started clusters we have seen
uint32_t totalClusterCount = 0;
uint32_t partClusterIndex = 0;
uint32_t partClusterCount = 0;
- for (i = result.mLigatureStart; i < result.mLigatureEnd; ++i) {
+ for (i = result.mRange.start; i < result.mRange.end; ++i) {
// Treat the first character of the ligature as the start of a
// cluster for our purposes of allocating ligature width to its
// characters.
- if (i == result.mLigatureStart || charGlyphs[i].IsClusterStart()) {
+ if (i == result.mRange.start || charGlyphs[i].IsClusterStart()) {
++totalClusterCount;
- if (i < aPartStart) {
+ if (i < aPartRange.start) {
++partClusterIndex;
- } else if (i < aPartEnd) {
+ } else if (i < aPartRange.end) {
++partClusterCount;
}
}
@@ -275,7 +274,7 @@ gfxTextRun::ComputeLigatureData(uint32_t aPartStart, uint32_t aPartEnd,
// Any rounding errors are apportioned to the final part of the ligature,
// so that measuring all parts of a ligature and summing them is equal to
// the ligature width.
- if (aPartEnd == result.mLigatureEnd) {
+ if (aPartRange.end == result.mRange.end) {
gfxFloat allParts = totalClusterCount * (ligatureWidth / totalClusterCount);
result.mPartWidth += ligatureWidth - allParts;
}
@@ -296,12 +295,14 @@ gfxTextRun::ComputeLigatureData(uint32_t aPartStart, uint32_t aPartEnd,
if (aProvider && (mFlags & gfxTextRunFactory::TEXT_ENABLE_SPACING)) {
gfxFont::Spacing spacing;
- if (aPartStart == result.mLigatureStart) {
- aProvider->GetSpacing(aPartStart, 1, &spacing);
+ if (aPartRange.start == result.mRange.start) {
+ aProvider->GetSpacing(
+ Range(aPartRange.start, aPartRange.start + 1), &spacing);
result.mPartWidth += spacing.mBefore;
}
- if (aPartEnd == result.mLigatureEnd) {
- aProvider->GetSpacing(aPartEnd - 1, 1, &spacing);
+ if (aPartRange.end == result.mRange.end) {
+ aProvider->GetSpacing(
+ Range(aPartRange.end - 1, aPartRange.end), &spacing);
result.mPartWidth += spacing.mAfter;
}
}
@@ -310,34 +311,34 @@ gfxTextRun::ComputeLigatureData(uint32_t aPartStart, uint32_t aPartEnd,
}
gfxFloat
-gfxTextRun::ComputePartialLigatureWidth(uint32_t aPartStart, uint32_t aPartEnd,
+gfxTextRun::ComputePartialLigatureWidth(Range aPartRange,
PropertyProvider *aProvider)
{
- if (aPartStart >= aPartEnd)
+ if (aPartRange.start >= aPartRange.end)
return 0;
- LigatureData data = ComputeLigatureData(aPartStart, aPartEnd, aProvider);
+ LigatureData data = ComputeLigatureData(aPartRange, aProvider);
return data.mPartWidth;
}
int32_t
-gfxTextRun::GetAdvanceForGlyphs(uint32_t aStart, uint32_t aEnd)
+gfxTextRun::GetAdvanceForGlyphs(Range aRange)
{
int32_t advance = 0;
- for (auto i = aStart; i < aEnd; ++i) {
+ for (auto i = aRange.start; i < aRange.end; ++i) {
advance += GetAdvanceForGlyph(i);
}
return advance;
}
static void
-GetAdjustedSpacing(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
+GetAdjustedSpacing(gfxTextRun *aTextRun, gfxTextRun::Range aRange,
gfxTextRun::PropertyProvider *aProvider,
gfxTextRun::PropertyProvider::Spacing *aSpacing)
{
- if (aStart >= aEnd)
+ if (aRange.start >= aRange.end)
return;
- aProvider->GetSpacing(aStart, aEnd - aStart, aSpacing);
+ aProvider->GetSpacing(aRange, aSpacing);
#ifdef DEBUG
// Check to see if we have spacing inside ligatures
@@ -345,11 +346,13 @@ GetAdjustedSpacing(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
const gfxTextRun::CompressedGlyph *charGlyphs = aTextRun->GetCharacterGlyphs();
uint32_t i;
- for (i = aStart; i < aEnd; ++i) {
+ for (i = aRange.start; i < aRange.end; ++i) {
if (!charGlyphs[i].IsLigatureGroupStart()) {
- NS_ASSERTION(i == aStart || aSpacing[i - aStart].mBefore == 0,
+ NS_ASSERTION(i == aRange.start ||
+ aSpacing[i - aRange.start].mBefore == 0,
"Before-spacing inside a ligature!");
- NS_ASSERTION(i - 1 <= aStart || aSpacing[i - 1 - aStart].mAfter == 0,
+ NS_ASSERTION(i - 1 <= aRange.start ||
+ aSpacing[i - 1 - aRange.start].mAfter == 0,
"After-spacing inside a ligature!");
}
}
@@ -357,51 +360,53 @@ GetAdjustedSpacing(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
}
bool
-gfxTextRun::GetAdjustedSpacingArray(uint32_t aStart, uint32_t aEnd,
- PropertyProvider *aProvider,
- uint32_t aSpacingStart, uint32_t aSpacingEnd,
+gfxTextRun::GetAdjustedSpacingArray(Range aRange, PropertyProvider *aProvider,
+ Range aSpacingRange,
nsTArray *aSpacing)
{
if (!aProvider || !(mFlags & gfxTextRunFactory::TEXT_ENABLE_SPACING))
return false;
- if (!aSpacing->AppendElements(aEnd - aStart))
+ if (!aSpacing->AppendElements(aRange.Length()))
return false;
- memset(aSpacing->Elements(), 0, sizeof(gfxFont::Spacing)*(aSpacingStart - aStart));
- GetAdjustedSpacing(this, aSpacingStart, aSpacingEnd, aProvider,
- aSpacing->Elements() + aSpacingStart - aStart);
- memset(aSpacing->Elements() + aSpacingEnd - aStart, 0, sizeof(gfxFont::Spacing)*(aEnd - aSpacingEnd));
+ auto spacingOffset = aSpacingRange.start - aRange.start;
+ memset(aSpacing->Elements(), 0, sizeof(gfxFont::Spacing) * spacingOffset);
+ GetAdjustedSpacing(this, aSpacingRange, aProvider,
+ aSpacing->Elements() + spacingOffset);
+ memset(aSpacing->Elements() + aSpacingRange.end - aRange.start, 0,
+ sizeof(gfxFont::Spacing) * (aRange.end - aSpacingRange.end));
return true;
}
void
-gfxTextRun::ShrinkToLigatureBoundaries(uint32_t *aStart, uint32_t *aEnd)
+gfxTextRun::ShrinkToLigatureBoundaries(Range* aRange)
{
- if (*aStart >= *aEnd)
+ if (aRange->start >= aRange->end)
return;
CompressedGlyph *charGlyphs = mCharacterGlyphs;
- while (*aStart < *aEnd && !charGlyphs[*aStart].IsLigatureGroupStart()) {
- ++(*aStart);
+ while (aRange->start < aRange->end &&
+ !charGlyphs[aRange->start].IsLigatureGroupStart()) {
+ ++aRange->start;
}
- if (*aEnd < GetLength()) {
- while (*aEnd > *aStart && !charGlyphs[*aEnd].IsLigatureGroupStart()) {
- --(*aEnd);
+ if (aRange->end < GetLength()) {
+ while (aRange->end > aRange->start &&
+ !charGlyphs[aRange->end].IsLigatureGroupStart()) {
+ --aRange->end;
}
}
}
void
-gfxTextRun::DrawGlyphs(gfxFont *aFont, uint32_t aStart, uint32_t aEnd,
- gfxPoint *aPt, PropertyProvider *aProvider,
- uint32_t aSpacingStart, uint32_t aSpacingEnd,
+gfxTextRun::DrawGlyphs(gfxFont *aFont, Range aRange, gfxPoint *aPt,
+ PropertyProvider *aProvider, Range aSpacingRange,
TextRunDrawParams& aParams, uint16_t aOrientation)
{
AutoTArray spacingBuffer;
- bool haveSpacing = GetAdjustedSpacingArray(aStart, aEnd, aProvider,
- aSpacingStart, aSpacingEnd, &spacingBuffer);
+ bool haveSpacing = GetAdjustedSpacingArray(aRange, aProvider,
+ aSpacingRange, &spacingBuffer);
aParams.spacing = haveSpacing ? spacingBuffer.Elements() : nullptr;
- aFont->Draw(this, aStart, aEnd, aPt, aParams, aOrientation);
+ aFont->Draw(this, aRange.start, aRange.end, aPt, aParams, aOrientation);
}
static void
@@ -429,16 +434,16 @@ ClipPartialLigature(const gfxTextRun* aTextRun,
}
void
-gfxTextRun::DrawPartialLigature(gfxFont *aFont, uint32_t aStart, uint32_t aEnd,
+gfxTextRun::DrawPartialLigature(gfxFont *aFont, Range aRange,
gfxPoint *aPt, PropertyProvider *aProvider,
TextRunDrawParams& aParams, uint16_t aOrientation)
{
- if (aStart >= aEnd) {
+ if (aRange.start >= aRange.end) {
return;
}
// Draw partial ligature. We hack this by clipping the ligature.
- LigatureData data = ComputeLigatureData(aStart, aEnd, aProvider);
+ LigatureData data = ComputeLigatureData(aRange, aProvider);
gfxRect clipExtents = aParams.context->GetClipExtents();
gfxFloat start, end;
if (aParams.isVerticalRun) {
@@ -473,8 +478,8 @@ gfxTextRun::DrawPartialLigature(gfxFont *aFont, uint32_t aStart, uint32_t aEnd,
pt = gfxPoint(aPt->x - aParams.direction * data.mPartAdvance, aPt->y);
}
- DrawGlyphs(aFont, data.mLigatureStart, data.mLigatureEnd, &pt,
- aProvider, aStart, aEnd, aParams, aOrientation);
+ DrawGlyphs(aFont, data.mRange, &pt,
+ aProvider, aRange, aParams, aOrientation);
aParams.context->Restore();
if (aParams.isVerticalRun) {
@@ -484,18 +489,31 @@ gfxTextRun::DrawPartialLigature(gfxFont *aFont, uint32_t aStart, uint32_t aEnd,
}
}
-// returns true if a glyph run is using a font with synthetic bolding enabled, false otherwise
+// Returns true if a glyph run is using a font with synthetic bolding enabled,
+// or a color font (COLR/SVG/sbix/CBDT), false otherwise. This is used to
+// check whether the text run needs to be explicitly composited in order to
+// support opacity.
static bool
-HasSyntheticBold(gfxTextRun *aRun, uint32_t aStart, uint32_t aLength)
+HasSyntheticBoldOrColor(gfxTextRun *aRun, gfxTextRun::Range aRange)
{
- gfxTextRun::GlyphRunIterator iter(aRun, aStart, aLength);
+ gfxTextRun::GlyphRunIterator iter(aRun, aRange);
while (iter.NextRun()) {
gfxFont *font = iter.GetGlyphRun()->mFont;
- if (font && font->IsSyntheticBold()) {
- return true;
+ if (font) {
+ if (font->IsSyntheticBold()) {
+ return true;
+ }
+ gfxFontEntry* fe = font->GetFontEntry();
+ if (fe->TryGetSVGData(font) || fe->TryGetColorGlyphs()) {
+ return true;
+ }
+#if defined(XP_MACOSX) // sbix fonts only supported via Core Text
+ if (fe->HasFontTable(TRUETYPE_TAG('s', 'b', 'i', 'x'))) {
+ return true;
+ }
+#endif
}
}
-
return false;
}
@@ -546,23 +564,20 @@ struct BufferAlphaColor {
};
void
-gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, DrawMode aDrawMode,
- uint32_t aStart, uint32_t aLength,
- PropertyProvider *aProvider, gfxFloat *aAdvanceWidth,
- gfxTextContextPaint *aContextPaint,
- gfxTextRunDrawCallbacks *aCallbacks)
+gfxTextRun::Draw(Range aRange, gfxPoint aPt, const DrawParams& aParams)
{
- NS_ASSERTION(aStart + aLength <= GetLength(), "Substring out of range");
- NS_ASSERTION(aDrawMode == DrawMode::GLYPH_PATH ||
- !(int(aDrawMode) & int(DrawMode::GLYPH_PATH)),
+ NS_ASSERTION(aRange.end <= GetLength(), "Substring out of range");
+ NS_ASSERTION(aParams.drawMode == DrawMode::GLYPH_PATH ||
+ !(int(aParams.drawMode) & int(DrawMode::GLYPH_PATH)),
"GLYPH_PATH cannot be used with GLYPH_FILL, GLYPH_STROKE or GLYPH_STROKE_UNDERNEATH");
- NS_ASSERTION(aDrawMode == DrawMode::GLYPH_PATH || !aCallbacks,
+ NS_ASSERTION(aParams.drawMode == DrawMode::GLYPH_PATH || !aParams.callbacks,
"callback must not be specified unless using GLYPH_PATH");
bool skipDrawing = mSkipDrawing;
- if (aDrawMode == DrawMode::GLYPH_FILL) {
+ if (aParams.drawMode == DrawMode::GLYPH_FILL) {
Color currentColor;
- if (aContext->GetDeviceColor(currentColor) && currentColor.a == 0) {
+ if (aParams.context->GetDeviceColor(currentColor) &&
+ currentColor.a == 0) {
skipDrawing = true;
}
}
@@ -572,12 +587,11 @@ gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, DrawMode aDrawMode,
if (skipDrawing) {
// We don't need to draw anything;
// but if the caller wants advance width, we need to compute it here
- if (aAdvanceWidth) {
- gfxTextRun::Metrics metrics = MeasureText(aStart, aLength,
- gfxFont::LOOSE_INK_EXTENTS,
- aContext->GetDrawTarget(),
- aProvider);
- *aAdvanceWidth = metrics.mAdvanceWidth * direction;
+ if (aParams.advanceWidth) {
+ gfxTextRun::Metrics metrics = MeasureText(
+ aRange, gfxFont::LOOSE_INK_EXTENTS,
+ aParams.context->GetDrawTarget(), aParams.provider);
+ *aParams.advanceWidth = metrics.mAdvanceWidth * direction;
}
// return without drawing
@@ -586,19 +600,18 @@ gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, DrawMode aDrawMode,
// synthetic bolding draws glyphs twice ==> colors with opacity won't draw
// correctly unless first drawn without alpha
- BufferAlphaColor syntheticBoldBuffer(aContext);
+ BufferAlphaColor syntheticBoldBuffer(aParams.context);
Color currentColor;
bool needToRestore = false;
- if (aDrawMode == DrawMode::GLYPH_FILL &&
- HasNonOpaqueNonTransparentColor(aContext, currentColor) &&
- HasSyntheticBold(this, aStart, aLength)) {
+ if (aParams.drawMode == DrawMode::GLYPH_FILL &&
+ HasNonOpaqueNonTransparentColor(aParams.context, currentColor) &&
+ HasSyntheticBoldOrColor(this, aRange)) {
needToRestore = true;
// measure text, use the bounding box
- gfxTextRun::Metrics metrics = MeasureText(aStart, aLength,
- gfxFont::LOOSE_INK_EXTENTS,
- aContext->GetDrawTarget(),
- aProvider);
+ gfxTextRun::Metrics metrics = MeasureText(
+ aRange, gfxFont::LOOSE_INK_EXTENTS,
+ aParams.context->GetDrawTarget(), aParams.provider);
metrics.mBoundingBox.MoveBy(aPt);
syntheticBoldBuffer.PushSolidColor(metrics.mBoundingBox, currentColor,
GetAppUnitsPerDevUnit());
@@ -607,46 +620,48 @@ gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, DrawMode aDrawMode,
// Set up parameters that will be constant across all glyph runs we need
// to draw, regardless of the font used.
TextRunDrawParams params;
- params.context = aContext;
+ params.context = aParams.context;
params.devPerApp = 1.0 / double(GetAppUnitsPerDevUnit());
params.isVerticalRun = IsVertical();
params.isRTL = IsRightToLeft();
params.direction = direction;
- params.drawMode = aDrawMode;
- params.callbacks = aCallbacks;
- params.runContextPaint = aContextPaint;
- params.paintSVGGlyphs = !aCallbacks || aCallbacks->mShouldPaintSVGGlyphs;
- params.dt = aContext->GetDrawTarget();
- params.fontSmoothingBGColor = aContext->GetFontSmoothingBackgroundColor();
+ params.drawMode = aParams.drawMode;
+ params.callbacks = aParams.callbacks;
+ params.runContextPaint = aParams.contextPaint;
+ params.paintSVGGlyphs = !aParams.callbacks ||
+ aParams.callbacks->mShouldPaintSVGGlyphs;
+ params.dt = aParams.context->GetDrawTarget();
+ params.fontSmoothingBGColor =
+ aParams.context->GetFontSmoothingBackgroundColor();
- GlyphRunIterator iter(this, aStart, aLength);
+ GlyphRunIterator iter(this, aRange);
gfxFloat advance = 0.0;
while (iter.NextRun()) {
gfxFont *font = iter.GetGlyphRun()->mFont;
uint32_t start = iter.GetStringStart();
uint32_t end = iter.GetStringEnd();
- uint32_t ligatureRunStart = start;
- uint32_t ligatureRunEnd = end;
- ShrinkToLigatureBoundaries(&ligatureRunStart, &ligatureRunEnd);
+ Range ligatureRange(start, end);
+ ShrinkToLigatureBoundaries(&ligatureRange);
- bool drawPartial = aDrawMode == DrawMode::GLYPH_FILL ||
- (aDrawMode == DrawMode::GLYPH_PATH && aCallbacks);
+ bool drawPartial = aParams.drawMode == DrawMode::GLYPH_FILL ||
+ (aParams.drawMode == DrawMode::GLYPH_PATH &&
+ aParams.callbacks);
gfxPoint origPt = aPt;
if (drawPartial) {
- DrawPartialLigature(font, start, ligatureRunStart, &aPt,
- aProvider, params,
+ DrawPartialLigature(font, Range(start, ligatureRange.start),
+ &aPt, aParams.provider, params,
iter.GetGlyphRun()->mOrientation);
}
- DrawGlyphs(font, ligatureRunStart, ligatureRunEnd, &aPt,
- aProvider, ligatureRunStart, ligatureRunEnd, params,
+ DrawGlyphs(font, ligatureRange, &aPt,
+ aParams.provider, ligatureRange, params,
iter.GetGlyphRun()->mOrientation);
if (drawPartial) {
- DrawPartialLigature(font, ligatureRunEnd, end, &aPt,
- aProvider, params,
+ DrawPartialLigature(font, Range(ligatureRange.end, end),
+ &aPt, aParams.provider, params,
iter.GetGlyphRun()->mOrientation);
}
@@ -662,8 +677,8 @@ gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, DrawMode aDrawMode,
syntheticBoldBuffer.PopAlpha();
}
- if (aAdvanceWidth) {
- *aAdvanceWidth = advance;
+ if (aParams.advanceWidth) {
+ *aParams.advanceWidth = advance;
}
}
@@ -671,10 +686,9 @@ gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, DrawMode aDrawMode,
void
gfxTextRun::DrawEmphasisMarks(gfxContext *aContext, gfxTextRun* aMark,
gfxFloat aMarkAdvance, gfxPoint aPt,
- uint32_t aStart, uint32_t aLength,
- PropertyProvider* aProvider)
+ Range aRange, PropertyProvider* aProvider)
{
- MOZ_ASSERT(aStart + aLength <= GetLength());
+ MOZ_ASSERT(aRange.end <= GetLength());
EmphasisMarkDrawParams params;
params.context = aContext;
@@ -686,69 +700,65 @@ gfxTextRun::DrawEmphasisMarks(gfxContext *aContext, gfxTextRun* aMark,
gfxFloat& inlineCoord = params.isVertical ? aPt.y : aPt.x;
gfxFloat direction = params.direction;
- GlyphRunIterator iter(this, aStart, aLength);
+ GlyphRunIterator iter(this, aRange);
while (iter.NextRun()) {
gfxFont* font = iter.GetGlyphRun()->mFont;
uint32_t start = iter.GetStringStart();
uint32_t end = iter.GetStringEnd();
- uint32_t ligatureRunStart = start;
- uint32_t ligatureRunEnd = end;
- ShrinkToLigatureBoundaries(&ligatureRunStart, &ligatureRunEnd);
+ Range ligatureRange(start, end);
+ ShrinkToLigatureBoundaries(&ligatureRange);
- inlineCoord += direction *
- ComputePartialLigatureWidth(start, ligatureRunStart, aProvider);
+ inlineCoord += direction * ComputePartialLigatureWidth(
+ Range(start, ligatureRange.start), aProvider);
AutoTArray spacingBuffer;
bool haveSpacing = GetAdjustedSpacingArray(
- ligatureRunStart, ligatureRunEnd, aProvider,
- ligatureRunStart, ligatureRunEnd, &spacingBuffer);
+ ligatureRange, aProvider, ligatureRange, &spacingBuffer);
params.spacing = haveSpacing ? spacingBuffer.Elements() : nullptr;
- font->DrawEmphasisMarks(this, &aPt, ligatureRunStart,
- ligatureRunEnd - ligatureRunStart, params);
+ font->DrawEmphasisMarks(this, &aPt, ligatureRange.start,
+ ligatureRange.Length(), params);
- inlineCoord += direction *
- ComputePartialLigatureWidth(ligatureRunEnd, end, aProvider);
+ inlineCoord += direction * ComputePartialLigatureWidth(
+ Range(ligatureRange.end, end), aProvider);
}
}
void
-gfxTextRun::AccumulateMetricsForRun(gfxFont *aFont,
- uint32_t aStart, uint32_t aEnd,
+gfxTextRun::AccumulateMetricsForRun(gfxFont *aFont, Range aRange,
gfxFont::BoundingBoxType aBoundingBoxType,
DrawTarget* aRefDrawTarget,
PropertyProvider *aProvider,
- uint32_t aSpacingStart, uint32_t aSpacingEnd,
+ Range aSpacingRange,
uint16_t aOrientation,
Metrics *aMetrics)
{
AutoTArray spacingBuffer;
- bool haveSpacing = GetAdjustedSpacingArray(aStart, aEnd, aProvider,
- aSpacingStart, aSpacingEnd, &spacingBuffer);
- Metrics metrics = aFont->Measure(this, aStart, aEnd, aBoundingBoxType,
- aRefDrawTarget,
+ bool haveSpacing = GetAdjustedSpacingArray(aRange, aProvider,
+ aSpacingRange, &spacingBuffer);
+ Metrics metrics = aFont->Measure(this, aRange.start, aRange.end,
+ aBoundingBoxType, aRefDrawTarget,
haveSpacing ? spacingBuffer.Elements() : nullptr,
aOrientation);
aMetrics->CombineWith(metrics, IsRightToLeft());
}
void
-gfxTextRun::AccumulatePartialLigatureMetrics(gfxFont *aFont,
- uint32_t aStart, uint32_t aEnd,
+gfxTextRun::AccumulatePartialLigatureMetrics(gfxFont *aFont, Range aRange,
gfxFont::BoundingBoxType aBoundingBoxType, DrawTarget* aRefDrawTarget,
PropertyProvider *aProvider, uint16_t aOrientation, Metrics *aMetrics)
{
- if (aStart >= aEnd)
+ if (aRange.start >= aRange.end)
return;
// Measure partial ligature. We hack this by clipping the metrics in the
// same way we clip the drawing.
- LigatureData data = ComputeLigatureData(aStart, aEnd, aProvider);
+ LigatureData data = ComputeLigatureData(aRange, aProvider);
// First measure the complete ligature
Metrics metrics;
- AccumulateMetricsForRun(aFont, data.mLigatureStart, data.mLigatureEnd,
+ AccumulateMetricsForRun(aFont, data.mRange,
aBoundingBoxType, aRefDrawTarget,
- aProvider, aStart, aEnd, aOrientation, &metrics);
+ aProvider, aRange, aOrientation, &metrics);
// Clip the bounding box to the ligature part
gfxFloat bboxLeft = metrics.mBoundingBox.X();
@@ -770,24 +780,24 @@ gfxTextRun::AccumulatePartialLigatureMetrics(gfxFont *aFont,
}
gfxTextRun::Metrics
-gfxTextRun::MeasureText(uint32_t aStart, uint32_t aLength,
+gfxTextRun::MeasureText(Range aRange,
gfxFont::BoundingBoxType aBoundingBoxType,
DrawTarget* aRefDrawTarget,
PropertyProvider *aProvider)
{
- NS_ASSERTION(aStart + aLength <= GetLength(), "Substring out of range");
+ NS_ASSERTION(aRange.end <= GetLength(), "Substring out of range");
Metrics accumulatedMetrics;
- GlyphRunIterator iter(this, aStart, aLength);
+ GlyphRunIterator iter(this, aRange);
while (iter.NextRun()) {
gfxFont *font = iter.GetGlyphRun()->mFont;
uint32_t start = iter.GetStringStart();
uint32_t end = iter.GetStringEnd();
- uint32_t ligatureRunStart = start;
- uint32_t ligatureRunEnd = end;
- ShrinkToLigatureBoundaries(&ligatureRunStart, &ligatureRunEnd);
+ Range ligatureRange(start, end);
+ ShrinkToLigatureBoundaries(&ligatureRange);
- AccumulatePartialLigatureMetrics(font, start, ligatureRunStart,
+ AccumulatePartialLigatureMetrics(
+ font, Range(start, ligatureRange.start),
aBoundingBoxType, aRefDrawTarget, aProvider,
iter.GetGlyphRun()->mOrientation, &accumulatedMetrics);
@@ -797,11 +807,12 @@ gfxTextRun::MeasureText(uint32_t aStart, uint32_t aLength,
// by getting some ascent/descent from the font and using our stored
// advance widths.
AccumulateMetricsForRun(font,
- ligatureRunStart, ligatureRunEnd, aBoundingBoxType,
- aRefDrawTarget, aProvider, ligatureRunStart, ligatureRunEnd,
+ ligatureRange, aBoundingBoxType,
+ aRefDrawTarget, aProvider, ligatureRange,
iter.GetGlyphRun()->mOrientation, &accumulatedMetrics);
- AccumulatePartialLigatureMetrics(font, ligatureRunEnd, end,
+ AccumulatePartialLigatureMetrics(
+ font, Range(ligatureRange.end, end),
aBoundingBoxType, aRefDrawTarget, aProvider,
iter.GetGlyphRun()->mOrientation, &accumulatedMetrics);
}
@@ -829,13 +840,12 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength,
NS_ASSERTION(aStart + aMaxLength <= GetLength(), "Substring out of range");
- uint32_t bufferStart = aStart;
- uint32_t bufferLength = std::min(aMaxLength, MEASUREMENT_BUFFER_SIZE);
+ Range bufferRange(aStart, aStart +
+ std::min(aMaxLength, MEASUREMENT_BUFFER_SIZE));
PropertyProvider::Spacing spacingBuffer[MEASUREMENT_BUFFER_SIZE];
bool haveSpacing = aProvider && (mFlags & gfxTextRunFactory::TEXT_ENABLE_SPACING) != 0;
if (haveSpacing) {
- GetAdjustedSpacing(this, bufferStart, bufferStart + bufferLength, aProvider,
- spacingBuffer);
+ GetAdjustedSpacing(this, bufferRange, aProvider, spacingBuffer);
}
bool hyphenBuffer[MEASUREMENT_BUFFER_SIZE];
bool haveHyphenation = aProvider &&
@@ -843,8 +853,7 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength,
(aProvider->GetHyphensOption() == NS_STYLE_HYPHENS_MANUAL &&
(mFlags & gfxTextRunFactory::TEXT_ENABLE_HYPHEN_BREAKS) != 0));
if (haveHyphenation) {
- aProvider->GetHyphenationBreaks(bufferStart, bufferLength,
- hyphenBuffer);
+ aProvider->GetHyphenationBreaks(bufferRange, hyphenBuffer);
}
gfxFloat width = 0;
@@ -860,23 +869,21 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength,
uint32_t end = aStart + aMaxLength;
bool lastBreakUsedHyphenation = false;
- uint32_t ligatureRunStart = aStart;
- uint32_t ligatureRunEnd = end;
- ShrinkToLigatureBoundaries(&ligatureRunStart, &ligatureRunEnd);
+ Range ligatureRange(aStart, end);
+ ShrinkToLigatureBoundaries(&ligatureRange);
uint32_t i;
for (i = aStart; i < end; ++i) {
- if (i >= bufferStart + bufferLength) {
+ if (i >= bufferRange.end) {
// Fetch more spacing and hyphenation data
- bufferStart = i;
- bufferLength = std::min(aStart + aMaxLength, i + MEASUREMENT_BUFFER_SIZE) - i;
+ bufferRange.start = i;
+ bufferRange.end = std::min(aStart + aMaxLength,
+ i + MEASUREMENT_BUFFER_SIZE);
if (haveSpacing) {
- GetAdjustedSpacing(this, bufferStart, bufferStart + bufferLength, aProvider,
- spacingBuffer);
+ GetAdjustedSpacing(this, bufferRange, aProvider, spacingBuffer);
}
if (haveHyphenation) {
- aProvider->GetHyphenationBreaks(bufferStart, bufferLength,
- hyphenBuffer);
+ aProvider->GetHyphenationBreaks(bufferRange, hyphenBuffer);
}
}
@@ -887,8 +894,8 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength,
if (aSuppressBreak != eSuppressAllBreaks &&
(aSuppressBreak != eSuppressInitialBreak || i > aStart)) {
bool atNaturalBreak = mCharacterGlyphs[i].CanBreakBefore() == 1;
- bool atHyphenationBreak =
- !atNaturalBreak && haveHyphenation && hyphenBuffer[i - bufferStart];
+ bool atHyphenationBreak = !atNaturalBreak &&
+ haveHyphenation && hyphenBuffer[i - bufferRange.start];
bool atBreak = atNaturalBreak || atHyphenationBreak;
bool wordWrapping =
aCanWordWrap && mCharacterGlyphs[i].IsClusterStart() &&
@@ -921,14 +928,16 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength,
}
gfxFloat charAdvance;
- if (i >= ligatureRunStart && i < ligatureRunEnd) {
- charAdvance = GetAdvanceForGlyphs(i, i + 1);
+ if (i >= ligatureRange.start && i < ligatureRange.end) {
+ charAdvance = GetAdvanceForGlyphs(Range(i, i + 1));
if (haveSpacing) {
- PropertyProvider::Spacing *space = &spacingBuffer[i - bufferStart];
+ PropertyProvider::Spacing *space =
+ &spacingBuffer[i - bufferRange.start];
charAdvance += space->mBefore + space->mAfter;
}
} else {
- charAdvance = ComputePartialLigatureWidth(i, i + 1, aProvider);
+ charAdvance =
+ ComputePartialLigatureWidth(Range(i, i + 1), aProvider);
}
advance += charAdvance;
@@ -965,13 +974,13 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength,
}
if (aMetrics) {
- *aMetrics = MeasureText(aStart, charsFit, aBoundingBoxType,
+ auto fitEnd = aStart + charsFit;
+ *aMetrics = MeasureText(Range(aStart, fitEnd), aBoundingBoxType,
aRefDrawTarget, aProvider);
if (trimmableChars) {
Metrics trimMetrics =
- MeasureText(aStart + charsFit - trimmableChars,
- trimmableChars, aBoundingBoxType,
- aRefDrawTarget, aProvider);
+ MeasureText(Range(fitEnd - trimmableChars, fitEnd),
+ aBoundingBoxType, aRefDrawTarget, aProvider);
aMetrics->mAdvanceWidth -= trimMetrics.mAdvanceWidth;
}
}
@@ -993,18 +1002,19 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength,
}
gfxFloat
-gfxTextRun::GetAdvanceWidth(uint32_t aStart, uint32_t aLength,
- PropertyProvider *aProvider,
+gfxTextRun::GetAdvanceWidth(Range aRange, PropertyProvider *aProvider,
PropertyProvider::Spacing* aSpacing)
{
- NS_ASSERTION(aStart + aLength <= GetLength(), "Substring out of range");
+ NS_ASSERTION(aRange.end <= GetLength(), "Substring out of range");
- uint32_t ligatureRunStart = aStart;
- uint32_t ligatureRunEnd = aStart + aLength;
- ShrinkToLigatureBoundaries(&ligatureRunStart, &ligatureRunEnd);
+ Range ligatureRange = aRange;
+ ShrinkToLigatureBoundaries(&ligatureRange);
- gfxFloat result = ComputePartialLigatureWidth(aStart, ligatureRunStart, aProvider) +
- ComputePartialLigatureWidth(ligatureRunEnd, aStart + aLength, aProvider);
+ gfxFloat result =
+ ComputePartialLigatureWidth(Range(aRange.start, ligatureRange.start),
+ aProvider) +
+ ComputePartialLigatureWidth(Range(ligatureRange.end, aRange.end),
+ aProvider);
if (aSpacing) {
aSpacing->mBefore = aSpacing->mAfter = 0;
@@ -1015,10 +1025,10 @@ gfxTextRun::GetAdvanceWidth(uint32_t aStart, uint32_t aLength,
if (aProvider && (mFlags & gfxTextRunFactory::TEXT_ENABLE_SPACING)) {
uint32_t i;
AutoTArray spacingBuffer;
- if (spacingBuffer.AppendElements(aLength)) {
- GetAdjustedSpacing(this, ligatureRunStart, ligatureRunEnd, aProvider,
+ if (spacingBuffer.AppendElements(aRange.Length())) {
+ GetAdjustedSpacing(this, ligatureRange, aProvider,
spacingBuffer.Elements());
- for (i = 0; i < ligatureRunEnd - ligatureRunStart; ++i) {
+ for (i = 0; i < ligatureRange.Length(); ++i) {
PropertyProvider::Spacing *space = &spacingBuffer[i];
result += space->mBefore + space->mAfter;
}
@@ -1029,11 +1039,11 @@ gfxTextRun::GetAdvanceWidth(uint32_t aStart, uint32_t aLength,
}
}
- return result + GetAdvanceForGlyphs(ligatureRunStart, ligatureRunEnd);
+ return result + GetAdvanceForGlyphs(ligatureRange);
}
bool
-gfxTextRun::SetLineBreaks(uint32_t aStart, uint32_t aLength,
+gfxTextRun::SetLineBreaks(Range aRange,
bool aLineBreakBefore, bool aLineBreakAfter,
gfxFloat *aAdvanceWidthDelta)
{
@@ -1231,12 +1241,11 @@ gfxTextRun::CopyGlyphDataFrom(gfxShapedWord *aShapedWord, uint32_t aOffset)
}
void
-gfxTextRun::CopyGlyphDataFrom(gfxTextRun *aSource, uint32_t aStart,
- uint32_t aLength, uint32_t aDest)
+gfxTextRun::CopyGlyphDataFrom(gfxTextRun *aSource, Range aRange, uint32_t aDest)
{
- NS_ASSERTION(aStart + aLength <= aSource->GetLength(),
+ NS_ASSERTION(aRange.end <= aSource->GetLength(),
"Source substring out of range");
- NS_ASSERTION(aDest + aLength <= GetLength(),
+ NS_ASSERTION(aDest + aRange.Length() <= GetLength(),
"Destination substring out of range");
if (aSource->mSkipDrawing) {
@@ -1244,9 +1253,9 @@ gfxTextRun::CopyGlyphDataFrom(gfxTextRun *aSource, uint32_t aStart,
}
// Copy base glyph data, and DetailedGlyph data where present
- const CompressedGlyph *srcGlyphs = aSource->mCharacterGlyphs + aStart;
+ const CompressedGlyph *srcGlyphs = aSource->mCharacterGlyphs + aRange.start;
CompressedGlyph *dstGlyphs = mCharacterGlyphs + aDest;
- for (uint32_t i = 0; i < aLength; ++i) {
+ for (uint32_t i = 0; i < aRange.Length(); ++i) {
CompressedGlyph g = srcGlyphs[i];
g.SetCanBreakBefore(!g.IsClusterStart() ?
CompressedGlyph::FLAG_BREAK_TYPE_NONE :
@@ -1256,7 +1265,8 @@ gfxTextRun::CopyGlyphDataFrom(gfxTextRun *aSource, uint32_t aStart,
if (count > 0) {
DetailedGlyph *dst = AllocateDetailedGlyphs(i + aDest, count);
if (dst) {
- DetailedGlyph *src = aSource->GetDetailedGlyphs(i + aStart);
+ DetailedGlyph *src =
+ aSource->GetDetailedGlyphs(i + aRange.start);
if (src) {
::memcpy(dst, src, count * sizeof(DetailedGlyph));
} else {
@@ -1271,7 +1281,7 @@ gfxTextRun::CopyGlyphDataFrom(gfxTextRun *aSource, uint32_t aStart,
}
// Copy glyph runs
- GlyphRunIterator iter(aSource, aStart, aLength);
+ GlyphRunIterator iter(aSource, aRange);
#ifdef DEBUG
GlyphRun *prevRun = nullptr;
#endif
@@ -1302,7 +1312,7 @@ gfxTextRun::CopyGlyphDataFrom(gfxTextRun *aSource, uint32_t aStart,
"Ended font run in the middle of a cluster");
nsresult rv = AddGlyphRun(font, iter.GetGlyphRun()->mMatchType,
- start - aStart + aDest, false,
+ start - aRange.start + aDest, false,
iter.GetGlyphRun()->mOrientation);
if (NS_FAILED(rv))
return;
@@ -1482,11 +1492,11 @@ gfxTextRun::ClusterIterator::NextCluster()
return false;
}
-uint32_t
-gfxTextRun::ClusterIterator::ClusterLength() const
+gfxTextRun::Range
+gfxTextRun::ClusterIterator::ClusterRange() const
{
if (mCurrentChar == uint32_t(-1)) {
- return 0;
+ return Range(0, 0);
}
uint32_t i = mCurrentChar,
@@ -1497,7 +1507,7 @@ gfxTextRun::ClusterIterator::ClusterLength() const
}
}
- return i - mCurrentChar;
+ return Range(mCurrentChar, i);
}
gfxFloat
@@ -1507,7 +1517,7 @@ gfxTextRun::ClusterIterator::ClusterAdvance(PropertyProvider *aProvider) const
return 0;
}
- return mTextRun->GetAdvanceWidth(mCurrentChar, ClusterLength(), aProvider);
+ return mTextRun->GetAdvanceWidth(ClusterRange(), aProvider);
}
size_t
@@ -1647,8 +1657,8 @@ gfxFontGroup::AddPlatformFont(const nsAString& aName,
}
// Not known in the user font set ==> check system fonts
+ gfxPlatformFontList* fontList = gfxPlatformFontList::PlatformFontList();
if (!family) {
- gfxPlatformFontList* fontList = gfxPlatformFontList::PlatformFontList();
family = fontList->FindFamily(aName, &mStyle, mDevToCssSize);
}
@@ -2056,8 +2066,7 @@ gfxFontGroup::GetHyphenWidth(gfxTextRun::PropertyProvider *aProvider)
nsAutoPtr
hyphRun(MakeHyphenTextRun(dt,
aProvider->GetAppUnitsPerDevUnit()));
- mHyphenWidth = hyphRun.get() ?
- hyphRun->GetAdvanceWidth(0, hyphRun->GetLength(), nullptr) : 0;
+ mHyphenWidth = hyphRun.get() ? hyphRun->GetAdvanceWidth() : 0;
}
}
return mHyphenWidth;
diff --git a/gfx/thebes/gfxTextRun.h b/gfx/thebes/gfxTextRun.h
index e1091085c5..60e2d3a39f 100644
--- a/gfx/thebes/gfxTextRun.h
+++ b/gfx/thebes/gfxTextRun.h
@@ -134,10 +134,23 @@ public:
return mCharacterGlyphs[aPos].CharMayHaveEmphasisMark();
}
- // All uint32_t aStart, uint32_t aLength ranges below are restricted to
- // grapheme cluster boundaries! All offsets are in terms of the string
- // passed into MakeTextRun.
-
+ // All offsets are in terms of the string passed into MakeTextRun.
+
+ // Describe range [start, end) of a text run. The range is
+ // restricted to grapheme cluster boundaries.
+ struct Range
+ {
+ uint32_t start;
+ uint32_t end;
+ uint32_t Length() const { return end - start; }
+
+ Range() : start(0), end(0) {}
+ Range(uint32_t aStart, uint32_t aEnd)
+ : start(aStart), end(aEnd) {}
+ explicit Range(gfxTextRun* aTextRun)
+ : start(0), end(aTextRun->GetLength()) {}
+ };
+
// All coordinates are in layout/app units
/**
@@ -152,8 +165,7 @@ public:
* @return true if this changed the linebreaks, false if the new line
* breaks are the same as the old
*/
- virtual bool SetPotentialLineBreaks(uint32_t aStart, uint32_t aLength,
- uint8_t *aBreakBefore);
+ virtual bool SetPotentialLineBreaks(Range aRange, uint8_t *aBreakBefore);
/**
* Layout provides PropertyProvider objects. These allow detection of
@@ -169,8 +181,7 @@ public:
public:
// Detect hyphenation break opportunities in the given range; breaks
// not at cluster boundaries will be ignored.
- virtual void GetHyphenationBreaks(uint32_t aStart, uint32_t aLength,
- bool *aBreakBefore) = 0;
+ virtual void GetHyphenationBreaks(Range aRange, bool *aBreakBefore) = 0;
// Returns the provider's hyphenation setting, so callers can decide
// whether it is necessary to call GetHyphenationBreaks.
@@ -189,8 +200,7 @@ public:
* CLUSTER_START, then character i-1 must have zero after-spacing and
* character i must have zero before-spacing.
*/
- virtual void GetSpacing(uint32_t aStart, uint32_t aLength,
- Spacing *aSpacing) = 0;
+ virtual void GetSpacing(Range aRange, Spacing *aSpacing) = 0;
// Returns a gfxContext that can be used to measure the hyphen glyph.
// Only called if the hyphen width is requested.
@@ -213,7 +223,7 @@ public:
return mCurrentChar;
}
- uint32_t ClusterLength() const;
+ Range ClusterRange() const;
gfxFloat ClusterAdvance(PropertyProvider *aProvider) const;
@@ -222,33 +232,39 @@ public:
uint32_t mCurrentChar;
};
+ struct DrawParams
+ {
+ gfxContext* context;
+ DrawMode drawMode = DrawMode::GLYPH_FILL;
+ PropertyProvider* provider = nullptr;
+ // If non-null, the advance width of the substring is set.
+ gfxFloat* advanceWidth = nullptr;
+ gfxTextContextPaint* contextPaint = nullptr;
+ gfxTextRunDrawCallbacks* callbacks = nullptr;
+ explicit DrawParams(gfxContext* aContext) : context(aContext) {}
+ };
+
/**
* Draws a substring. Uses only GetSpacing from aBreakProvider.
* The provided point is the baseline origin on the left of the string
* for LTR, on the right of the string for RTL.
- * @param aAdvanceWidth if non-null, the advance width of the substring
- * is returned here.
*
* Drawing should respect advance widths in the sense that for LTR runs,
- * Draw(ctx, pt, offset1, length1, dirty, &provider, &advance) followed by
- * Draw(ctx, gfxPoint(pt.x + advance, pt.y), offset1 + length1, length2,
- * dirty, &provider, nullptr) should have the same effect as
- * Draw(ctx, pt, offset1, length1+length2, dirty, &provider, nullptr).
+ * Draw(Range(start, middle), pt, ...) followed by
+ * Draw(Range(middle, end), gfxPoint(pt.x + advance, pt.y), ...)
+ * should have the same effect as
+ * Draw(Range(start, end), pt, ...)
+ *
* For RTL runs the rule is:
- * Draw(ctx, pt, offset1 + length1, length2, dirty, &provider, &advance) followed by
- * Draw(ctx, gfxPoint(pt.x + advance, pt.y), offset1, length1,
- * dirty, &provider, nullptr) should have the same effect as
- * Draw(ctx, pt, offset1, length1+length2, dirty, &provider, nullptr).
+ * Draw(Range(middle, end), pt, ...) followed by
+ * Draw(Range(start, middle), gfxPoint(pt.x + advance, pt.y), ...)
+ * should have the same effect as
+ * Draw(Range(start, end), pt, ...)
*
* Glyphs should be drawn in logical content order, which can be significant
* if they overlap (perhaps due to negative spacing).
*/
- void Draw(gfxContext *aContext, gfxPoint aPt,
- DrawMode aDrawMode,
- uint32_t aStart, uint32_t aLength,
- PropertyProvider *aProvider,
- gfxFloat *aAdvanceWidth, gfxTextContextPaint *aContextPaint,
- gfxTextRunDrawCallbacks *aCallbacks = nullptr);
+ void Draw(Range aRange, gfxPoint aPt, const DrawParams& aParams);
/**
* Draws the emphasis marks for this text run. Uses only GetSpacing
@@ -257,19 +273,25 @@ public:
*/
void DrawEmphasisMarks(gfxContext* aContext, gfxTextRun* aMark,
gfxFloat aMarkAdvance, gfxPoint aPt,
- uint32_t aStart, uint32_t aLength,
- PropertyProvider* aProvider);
+ Range aRange, PropertyProvider* aProvider);
/**
* Computes the ReflowMetrics for a substring.
* Uses GetSpacing from aBreakProvider.
* @param aBoundingBoxType which kind of bounding box (loose/tight)
*/
- Metrics MeasureText(uint32_t aStart, uint32_t aLength,
+ Metrics MeasureText(Range aRange,
gfxFont::BoundingBoxType aBoundingBoxType,
DrawTarget* aDrawTargetForTightBoundingBox,
PropertyProvider* aProvider);
+ Metrics MeasureText(gfxFont::BoundingBoxType aBoundingBoxType,
+ DrawTarget* aDrawTargetForTightBoundingBox,
+ PropertyProvider* aProvider = nullptr) {
+ return MeasureText(Range(this), aBoundingBoxType,
+ aDrawTargetForTightBoundingBox, aProvider);
+ }
+
/**
* Computes just the advance width for a substring.
* Uses GetSpacing from aBreakProvider.
@@ -277,13 +299,16 @@ public:
* the substring would be returned in it. NOTE: the spacing is
* included in the advance width.
*/
- gfxFloat GetAdvanceWidth(uint32_t aStart, uint32_t aLength,
- PropertyProvider *aProvider,
+ gfxFloat GetAdvanceWidth(Range aRange, PropertyProvider *aProvider,
PropertyProvider::Spacing* aSpacing = nullptr);
+ gfxFloat GetAdvanceWidth() {
+ return GetAdvanceWidth(Range(this), nullptr);
+ }
+
/**
* Clear all stored line breaks for the given range (both before and after),
- * and then set the line-break state before aStart to aBreakBefore and
+ * and then set the line-break state before aRange.start to aBreakBefore and
* after the last cluster to aBreakAfter.
*
* We require that before and after line breaks be consistent. For clusters
@@ -308,9 +333,9 @@ public:
* @param aAdvanceWidthDelta if non-null, returns the change in advance
* width of the given range.
*/
- virtual bool SetLineBreaks(uint32_t aStart, uint32_t aLength,
- bool aLineBreakBefore, bool aLineBreakAfter,
- gfxFloat* aAdvanceWidthDelta);
+ virtual bool SetLineBreaks(Range aRange,
+ bool aLineBreakBefore, bool aLineBreakAfter,
+ gfxFloat* aAdvanceWidthDelta);
enum SuppressBreak {
eNoSuppressBreak,
@@ -423,9 +448,11 @@ public:
class GlyphRunIterator {
public:
- GlyphRunIterator(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aLength)
- : mTextRun(aTextRun), mStartOffset(aStart), mEndOffset(aStart + aLength) {
- mNextIndex = mTextRun->FindFirstGlyphRunContaining(aStart);
+ GlyphRunIterator(gfxTextRun *aTextRun, Range aRange)
+ : mTextRun(aTextRun)
+ , mStartOffset(aRange.start)
+ , mEndOffset(aRange.end) {
+ mNextIndex = mTextRun->FindFirstGlyphRunContaining(aRange.start);
}
bool NextRun();
GlyphRun *GetGlyphRun() { return mGlyphRun; }
@@ -546,8 +573,7 @@ public:
// Copy glyph data for a range of characters from aSource to this
// textrun.
- void CopyGlyphDataFrom(gfxTextRun *aSource, uint32_t aStart,
- uint32_t aLength, uint32_t aDest);
+ void CopyGlyphDataFrom(gfxTextRun *aSource, Range aRange, uint32_t aDest);
nsExpirationState *GetExpirationState() { return &mExpirationState; }
@@ -560,9 +586,8 @@ public:
void ReleaseFontGroup();
struct LigatureData {
- // textrun offsets of the start and end of the containing ligature
- uint32_t mLigatureStart;
- uint32_t mLigatureEnd;
+ // textrun range of the containing ligature
+ Range mRange;
// appunits advance to the start of the ligature part within the ligature;
// never includes any spacing
gfxFloat mPartAdvance;
@@ -658,16 +683,15 @@ private:
// **** general helpers ****
// Get the total advance for a range of glyphs.
- int32_t GetAdvanceForGlyphs(uint32_t aStart, uint32_t aEnd);
+ int32_t GetAdvanceForGlyphs(Range aRange);
// Spacing for characters outside the range aSpacingStart/aSpacingEnd
// is assumed to be zero; such characters are not passed to aProvider.
// This is useful to protect aProvider from being passed character indices
// it is not currently able to handle.
- bool GetAdjustedSpacingArray(uint32_t aStart, uint32_t aEnd,
- PropertyProvider *aProvider,
- uint32_t aSpacingStart, uint32_t aSpacingEnd,
- nsTArray *aSpacing);
+ bool GetAdjustedSpacingArray(Range aRange, PropertyProvider *aProvider,
+ Range aSpacingRange,
+ nsTArray *aSpacing);
CompressedGlyph& EnsureComplexGlyph(uint32_t aIndex)
{
@@ -680,20 +704,20 @@ private:
// to handle requests that begin or end inside a ligature)
// if aProvider is null then mBeforeSpacing and mAfterSpacing are set to zero
- LigatureData ComputeLigatureData(uint32_t aPartStart, uint32_t aPartEnd,
+ LigatureData ComputeLigatureData(Range aPartRange,
PropertyProvider *aProvider);
- gfxFloat ComputePartialLigatureWidth(uint32_t aPartStart, uint32_t aPartEnd,
+ gfxFloat ComputePartialLigatureWidth(Range aPartRange,
PropertyProvider *aProvider);
- void DrawPartialLigature(gfxFont *aFont, uint32_t aStart, uint32_t aEnd,
+ void DrawPartialLigature(gfxFont *aFont, Range aRange,
gfxPoint *aPt, PropertyProvider *aProvider,
TextRunDrawParams& aParams, uint16_t aOrientation);
- // Advance aStart to the start of the nearest ligature; back up aEnd
- // to the nearest ligature end; may result in *aStart == *aEnd
- void ShrinkToLigatureBoundaries(uint32_t *aStart, uint32_t *aEnd);
+ // Advance aRange.start to the start of the nearest ligature, back
+ // up aRange.end to the nearest ligature end; may result in
+ // aRange->start == aRange->end.
+ void ShrinkToLigatureBoundaries(Range* aRange);
// result in appunits
- gfxFloat GetPartialLigatureWidth(uint32_t aStart, uint32_t aEnd, PropertyProvider *aProvider);
- void AccumulatePartialLigatureMetrics(gfxFont *aFont,
- uint32_t aStart, uint32_t aEnd,
+ gfxFloat GetPartialLigatureWidth(Range aRange, PropertyProvider *aProvider);
+ void AccumulatePartialLigatureMetrics(gfxFont *aFont, Range aRange,
gfxFont::BoundingBoxType aBoundingBoxType,
DrawTarget* aRefDrawTarget,
PropertyProvider *aProvider,
@@ -701,18 +725,17 @@ private:
Metrics *aMetrics);
// **** measurement helper ****
- void AccumulateMetricsForRun(gfxFont *aFont, uint32_t aStart, uint32_t aEnd,
+ void AccumulateMetricsForRun(gfxFont *aFont, Range aRange,
gfxFont::BoundingBoxType aBoundingBoxType,
DrawTarget* aRefDrawTarget,
PropertyProvider *aProvider,
- uint32_t aSpacingStart, uint32_t aSpacingEnd,
+ Range aSpacingRange,
uint16_t aOrientation,
Metrics *aMetrics);
// **** drawing helper ****
- void DrawGlyphs(gfxFont *aFont, uint32_t aStart, uint32_t aEnd,
- gfxPoint *aPt, PropertyProvider *aProvider,
- uint32_t aSpacingStart, uint32_t aSpacingEnd,
+ void DrawGlyphs(gfxFont *aFont, Range aRange, gfxPoint *aPt,
+ PropertyProvider *aProvider, Range aSpacingRange,
TextRunDrawParams& aParams, uint16_t aOrientation);
// XXX this should be changed to a GlyphRun plus a maybe-null GlyphRun*,
diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp
index a882007c3c..1beced6b73 100644
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -533,6 +533,15 @@ gfxWindowsPlatform::UpdateRenderMode()
}
}
+void
+gfxWindowsPlatform::ForceDeviceReset(ForcedDeviceResetReason aReason)
+{
+ Telemetry::Accumulate(Telemetry::FORCED_DEVICE_RESET_REASON, uint32_t(aReason));
+
+ mDeviceResetReason = DeviceResetReason::FORCED_RESET;
+ mHasDeviceReset = true;
+}
+
mozilla::gfx::BackendType
gfxWindowsPlatform::GetContentBackendFor(mozilla::layers::LayersBackend aLayers)
{
diff --git a/gfx/thebes/gfxWindowsPlatform.h b/gfx/thebes/gfxWindowsPlatform.h
index 1b99fbe42c..51011799ef 100644
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -145,6 +145,11 @@ public:
*/
void UpdateRenderMode();
+ /**
+ * Forces all GPU resources to be recreated on the next frame.
+ */
+ void ForceDeviceReset(ForcedDeviceResetReason aReason);
+
/**
* Verifies a D2D device is present and working, will attempt to create one
* it is non-functional or non-existant.
diff --git a/gfx/vr/gfxVROculus.cpp b/gfx/vr/gfxVROculus.cpp
index 0ebef17059..ef76f70c7a 100644
--- a/gfx/vr/gfxVROculus.cpp
+++ b/gfx/vr/gfxVROculus.cpp
@@ -148,7 +148,6 @@ InitializeOculusCAPI()
}
if (!ovrlib) {
- printf_stderr("Failed to load Oculus VR library!\n");
return false;
}
}
diff --git a/gfx/vr/gfxVROculus050.cpp b/gfx/vr/gfxVROculus050.cpp
index fe93cee841..dd526d3a48 100644
--- a/gfx/vr/gfxVROculus050.cpp
+++ b/gfx/vr/gfxVROculus050.cpp
@@ -153,7 +153,6 @@ InitializeOculusCAPI()
}
if (!ovrlib) {
- printf_stderr("Failed to load Oculus VR library!\n");
return false;
}
}
diff --git a/gfx/vr/ipc/VRManagerParent.cpp b/gfx/vr/ipc/VRManagerParent.cpp
index 56a2b865ec..0080323cf0 100644
--- a/gfx/vr/ipc/VRManagerParent.cpp
+++ b/gfx/vr/ipc/VRManagerParent.cpp
@@ -106,7 +106,6 @@ VRManagerParent::CreateSameProcess()
void
VRManagerParent::DeferredDestroy()
{
- MOZ_ASSERT(mCompositorThreadHolder);
mCompositorThreadHolder = nullptr;
mSelfRef = nullptr;
}
diff --git a/hal/gonk/GonkFMRadio.cpp b/hal/gonk/GonkFMRadio.cpp
index 383e98f428..a88d544f60 100644
--- a/hal/gonk/GonkFMRadio.cpp
+++ b/hal/gonk/GonkFMRadio.cpp
@@ -78,7 +78,7 @@ static bool sRDSSupported;
static int
setControl(uint32_t id, int32_t value)
{
- struct v4l2_control control;
+ struct v4l2_control control = {0};
control.id = id;
control.value = value;
return ioctl(sRadioFD, VIDIOC_S_CTRL, &control);
@@ -309,7 +309,7 @@ EnableFMRadio(const hal::FMRadioSettings& aInfo)
return;
}
- struct v4l2_capability cap;
+ struct v4l2_capability cap = {{0}};
int rc = ioctl(fd, VIDIOC_QUERYCAP, &cap);
if (rc < 0) {
HAL_LOG("Unable to query radio device");
@@ -487,7 +487,7 @@ GetFMRadioFrequency()
if (!sRadioEnabled)
return 0;
- struct v4l2_frequency freq;
+ struct v4l2_frequency freq = {0};
int rc = ioctl(sRadioFD, VIDIOC_G_FREQUENCY, &freq);
if (rc < 0) {
HAL_LOG("Could not get radio frequency");
diff --git a/hal/gonk/GonkHal.cpp b/hal/gonk/GonkHal.cpp
index e87496bb25..a6f02ac993 100644
--- a/hal/gonk/GonkHal.cpp
+++ b/hal/gonk/GonkHal.cpp
@@ -297,6 +297,9 @@ public:
static bool ShuttingDown() { return sShuttingDown; }
+protected:
+ ~VibratorRunnable() {}
+
private:
Monitor mMonitor;
@@ -471,7 +474,7 @@ public:
} // namespace
-class BatteryObserver : public IUeventObserver
+class BatteryObserver final : public IUeventObserver
{
public:
NS_INLINE_DECL_REFCOUNTING(BatteryObserver)
@@ -495,6 +498,9 @@ public:
}
}
+protected:
+ ~BatteryObserver() {}
+
private:
RefPtr mUpdater;
};
@@ -603,6 +609,11 @@ void
GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
{
int charge;
+ static bool previousCharging = false;
+ static double previousLevel = 0.0, remainingTime = 0.0;
+ static struct timespec lastLevelChange;
+ struct timespec now;
+ double dtime, dlevel;
if (GetCurrentBatteryCharge(&charge)) {
aBatteryInfo->level() = (double)charge / 100.0;
@@ -618,11 +629,81 @@ GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
aBatteryInfo->charging() = true;
}
- if (!aBatteryInfo->charging() || (aBatteryInfo->level() < 1.0)) {
+ if (aBatteryInfo->charging() != previousCharging){
aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime;
- } else {
- aBatteryInfo->remainingTime() = dom::battery::kDefaultRemainingTime;
+ memset(&lastLevelChange, 0, sizeof(struct timespec));
+ remainingTime = 0.0;
}
+
+ if (aBatteryInfo->charging()) {
+ if (aBatteryInfo->level() == 1.0) {
+ aBatteryInfo->remainingTime() = dom::battery::kDefaultRemainingTime;
+ } else if (aBatteryInfo->level() != previousLevel){
+ if (lastLevelChange.tv_sec != 0) {
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ dtime = now.tv_sec - lastLevelChange.tv_sec;
+ dlevel = aBatteryInfo->level() - previousLevel;
+
+ if (dlevel <= 0.0) {
+ aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime;
+ } else {
+ remainingTime = (double) round(dtime / dlevel * (1.0 - aBatteryInfo->level()));
+ aBatteryInfo->remainingTime() = remainingTime;
+ }
+
+ lastLevelChange = now;
+ } else { // lastLevelChange.tv_sec == 0
+ clock_gettime(CLOCK_MONOTONIC, &lastLevelChange);
+ aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime;
+ }
+
+ } else {
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ dtime = now.tv_sec - lastLevelChange.tv_sec;
+ if (dtime < remainingTime) {
+ aBatteryInfo->remainingTime() = round(remainingTime - dtime);
+ } else {
+ aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime;
+ }
+
+ }
+
+ } else {
+ if (aBatteryInfo->level() == 0.0) {
+ aBatteryInfo->remainingTime() = dom::battery::kDefaultRemainingTime;
+ } else if (aBatteryInfo->level() != previousLevel){
+ if (lastLevelChange.tv_sec != 0) {
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ dtime = now.tv_sec - lastLevelChange.tv_sec;
+ dlevel = previousLevel - aBatteryInfo->level();
+
+ if (dlevel <= 0.0) {
+ aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime;
+ } else {
+ remainingTime = (double) round(dtime / dlevel * aBatteryInfo->level());
+ aBatteryInfo->remainingTime() = remainingTime;
+ }
+
+ lastLevelChange = now;
+ } else { // lastLevelChange.tv_sec == 0
+ clock_gettime(CLOCK_MONOTONIC, &lastLevelChange);
+ aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime;
+ }
+
+ } else {
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ dtime = now.tv_sec - lastLevelChange.tv_sec;
+ if (dtime < remainingTime) {
+ aBatteryInfo->remainingTime() = round(remainingTime - dtime);
+ } else {
+ aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime;
+ }
+
+ }
+ }
+
+ previousCharging = aBatteryInfo->charging();
+ previousLevel = aBatteryInfo->level();
}
namespace {
@@ -662,8 +743,11 @@ bool
GetKeyLightEnabled()
{
LightConfiguration config;
- GetLight(eHalLightID_Buttons, &config);
- return (config.color != 0x00000000);
+ bool ok = GetLight(eHalLightID_Buttons, &config);
+ if (ok) {
+ return (config.color != 0x00000000);
+ }
+ return false;
}
void
@@ -696,10 +780,15 @@ GetScreenBrightness()
LightConfiguration config;
LightType light = eHalLightID_Backlight;
- GetLight(light, &config);
- // backlight is brightness only, so using one of the RGB elements as value.
- int brightness = config.color & 0xFF;
- return brightness / 255.0;
+ bool ok = GetLight(light, &config);
+ if (ok) {
+ // backlight is brightness only, so using one of the RGB elements as value.
+ int brightness = config.color & 0xFF;
+ return brightness / 255.0;
+ }
+ // If GetLight fails, it's because the light doesn't exist. So return
+ // a value corresponding to "off".
+ return 0;
}
void
@@ -1152,6 +1241,10 @@ public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
+
+protected:
+ ~OomVictimLogger() {}
+
private:
double mLastLineChecked;
ScopedFreePtr mRegexes;
@@ -1541,8 +1634,12 @@ PriorityClass::PriorityClass(ProcessPriority aPriority)
PriorityClass::~PriorityClass()
{
- close(mCpuCGroupProcsFd);
- close(mMemCGroupProcsFd);
+ if (mCpuCGroupProcsFd != -1) {
+ close(mCpuCGroupProcsFd);
+ }
+ if (mMemCGroupProcsFd != -1) {
+ close(mMemCGroupProcsFd);
+ }
}
PriorityClass::PriorityClass(const PriorityClass& aOther)
diff --git a/hal/gonk/GonkSensor.cpp b/hal/gonk/GonkSensor.cpp
index 9f94e9b692..f361e064be 100644
--- a/hal/gonk/GonkSensor.cpp
+++ b/hal/gonk/GonkSensor.cpp
@@ -18,10 +18,14 @@
#include
#include "mozilla/DebugOnly.h"
+#include "mozilla/Saturate.h"
#include "base/basictypes.h"
#include "base/thread.h"
+#include "GonkSensorsInterface.h"
+#include "GonkSensorsPollInterface.h"
+#include "GonkSensorsRegistryInterface.h"
#include "Hal.h"
#include "HalLog.h"
#include "HalSensor.h"
@@ -32,6 +36,10 @@ using namespace mozilla::hal;
namespace mozilla {
+//
+// Internal implementation
+//
+
// The value from SensorDevice.h (Android)
#define DEFAULT_DEVICE_POLL_RATE 200000000 /*200ms*/
// ProcessOrientation.cpp needs smaller poll rate to detect delay between
@@ -285,8 +293,8 @@ SetSensorState(SensorType aSensor, bool activate)
}
}
-void
-EnableSensorNotifications(SensorType aSensor)
+static void
+EnableSensorNotificationsInternal(SensorType aSensor)
{
if (!sSensorModule) {
hw_get_module(SENSORS_HARDWARE_MODULE_ID,
@@ -322,8 +330,8 @@ EnableSensorNotifications(SensorType aSensor)
SetSensorState(aSensor, true);
}
-void
-DisableSensorNotifications(SensorType aSensor)
+static void
+DisableSensorNotificationsInternal(SensorType aSensor)
{
if (!sSensorModule) {
return;
@@ -331,5 +339,522 @@ DisableSensorNotifications(SensorType aSensor)
SetSensorState(aSensor, false);
}
+//
+// Daemon
+//
+
+typedef detail::SaturateOp SaturateOpUint32;
+
+/**
+ * The poll notification handler receives all events about sensors and
+ * sensor events.
+ */
+class SensorsPollNotificationHandler final
+ : public GonkSensorsPollNotificationHandler
+{
+public:
+ SensorsPollNotificationHandler(GonkSensorsPollInterface* aPollInterface)
+ : mPollInterface(aPollInterface)
+ {
+ MOZ_ASSERT(mPollInterface);
+
+ mPollInterface->SetNotificationHandler(this);
+ }
+
+ void EnableSensorsByType(SensorsType aType)
+ {
+ if (SaturateOpUint32(mClasses[aType].mActivated)++) {
+ return;
+ }
+
+ SensorsDeliveryMode deliveryMode = DefaultSensorsDeliveryMode(aType);
+
+ // Old ref-count for the sensor type was 0, so we
+ // activate all sensors of the type.
+ for (size_t i = 0; i < mSensors.Length(); ++i) {
+ if (mSensors[i].mType == aType &&
+ mSensors[i].mDeliveryMode == deliveryMode) {
+ mPollInterface->EnableSensor(mSensors[i].mId, nullptr);
+ mPollInterface->SetPeriod(mSensors[i].mId, DefaultSensorPeriod(aType),
+ nullptr);
+ }
+ }
+ }
+
+ void DisableSensorsByType(SensorsType aType)
+ {
+ if (SaturateOpUint32(mClasses[aType].mActivated)-- != 1) {
+ return;
+ }
+
+ SensorsDeliveryMode deliveryMode = DefaultSensorsDeliveryMode(aType);
+
+ // Old ref-count for the sensor type was 1, so we
+ // deactivate all sensors of the type.
+ for (size_t i = 0; i < mSensors.Length(); ++i) {
+ if (mSensors[i].mType == aType &&
+ mSensors[i].mDeliveryMode == deliveryMode) {
+ mPollInterface->DisableSensor(mSensors[i].mId, nullptr);
+ }
+ }
+ }
+
+ void ClearSensorClasses()
+ {
+ for (size_t i = 0; i < MOZ_ARRAY_LENGTH(mClasses); ++i) {
+ mClasses[i] = SensorsSensorClass();
+ }
+ }
+
+ void ClearSensors()
+ {
+ mSensors.Clear();
+ }
+
+ // Methods for SensorsPollNotificationHandler
+ //
+
+ void ErrorNotification(SensorsError aError) override
+ {
+ // XXX: Bug 1206056: Try to repair some of the errors or restart cleanly.
+ }
+
+ void SensorDetectedNotification(int32_t aId, SensorsType aType,
+ float aRange, float aResolution,
+ float aPower, int32_t aMinPeriod,
+ int32_t aMaxPeriod,
+ SensorsTriggerMode aTriggerMode,
+ SensorsDeliveryMode aDeliveryMode) override
+ {
+ auto i = FindSensorIndexById(aId);
+ if (i == -1) {
+ // Add a new sensor...
+ i = mSensors.Length();
+ mSensors.AppendElement(SensorsSensor(aId, aType, aRange, aResolution,
+ aPower, aMinPeriod, aMaxPeriod,
+ aTriggerMode, aDeliveryMode));
+ } else {
+ // ...or update an existing one.
+ mSensors[i] = SensorsSensor(aId, aType, aRange, aResolution, aPower,
+ aMinPeriod, aMaxPeriod, aTriggerMode,
+ aDeliveryMode);
+ }
+
+ mClasses[aType].UpdateFromSensor(mSensors[i]);
+
+ if (mClasses[aType].mActivated &&
+ mSensors[i].mDeliveryMode == DefaultSensorsDeliveryMode(aType)) {
+ // The new sensor's type is enabled, so enable sensor.
+ mPollInterface->EnableSensor(aId, nullptr);
+ mPollInterface->SetPeriod(mSensors[i].mId, DefaultSensorPeriod(aType),
+ nullptr);
+ }
+ }
+
+ void SensorLostNotification(int32_t aId) override
+ {
+ auto i = FindSensorIndexById(aId);
+ if (i != -1) {
+ mSensors.RemoveElementAt(i);
+ }
+ }
+
+ void EventNotification(int32_t aId, const SensorsEvent& aEvent) override
+ {
+ auto i = FindSensorIndexById(aId);
+ if (i == -1) {
+ HAL_ERR("Sensor %d not registered", aId);
+ return;
+ }
+
+ SensorData sensorData;
+ auto rv = CreateSensorData(aEvent, mClasses[mSensors[i].mType],
+ sensorData);
+ if (NS_FAILED(rv)) {
+ return;
+ }
+
+ NotifySensorChange(sensorData);
+ }
+
+private:
+ ssize_t FindSensorIndexById(int32_t aId) const
+ {
+ for (size_t i = 0; i < mSensors.Length(); ++i) {
+ if (mSensors[i].mId == aId) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ uint64_t DefaultSensorPeriod(SensorsType aType) const
+ {
+ return aType == SENSORS_TYPE_ACCELEROMETER ? ACCELEROMETER_POLL_RATE
+ : DEFAULT_DEVICE_POLL_RATE;
+ }
+
+ SensorsDeliveryMode DefaultSensorsDeliveryMode(SensorsType aType) const
+ {
+ if (aType == SENSORS_TYPE_PROXIMITY ||
+ aType == SENSORS_TYPE_SIGNIFICANT_MOTION) {
+ return SENSORS_DELIVERY_MODE_IMMEDIATE;
+ }
+ return SENSORS_DELIVERY_MODE_BEST_EFFORT;
+ }
+
+ SensorType HardwareSensorToHalSensor(SensorsType aType) const
+ {
+ // FIXME: bug 802004, add proper support for the magnetic-field sensor.
+ switch (aType) {
+ case SENSORS_TYPE_ORIENTATION:
+ return SENSOR_ORIENTATION;
+ case SENSORS_TYPE_ACCELEROMETER:
+ return SENSOR_ACCELERATION;
+ case SENSORS_TYPE_PROXIMITY:
+ return SENSOR_PROXIMITY;
+ case SENSORS_TYPE_LIGHT:
+ return SENSOR_LIGHT;
+ case SENSORS_TYPE_GYROSCOPE:
+ return SENSOR_GYROSCOPE;
+ case SENSORS_TYPE_LINEAR_ACCELERATION:
+ return SENSOR_LINEAR_ACCELERATION;
+ case SENSORS_TYPE_ROTATION_VECTOR:
+ return SENSOR_ROTATION_VECTOR;
+ case SENSORS_TYPE_GAME_ROTATION_VECTOR:
+ return SENSOR_GAME_ROTATION_VECTOR;
+ default:
+ NS_NOTREACHED("Invalid sensors type");
+ }
+ return SENSOR_UNKNOWN;
+ }
+
+ SensorAccuracyType HardwareStatusToHalAccuracy(SensorsStatus aStatus) const
+ {
+ return static_cast(aStatus - 1);
+ }
+
+ nsresult CreateSensorData(const SensorsEvent& aEvent,
+ const SensorsSensorClass& aSensorClass,
+ SensorData& aSensorData) const
+ {
+ AutoTArray sensorValues;
+
+ auto sensor = HardwareSensorToHalSensor(aEvent.mType);
+
+ if (sensor == SENSOR_UNKNOWN) {
+ return NS_ERROR_ILLEGAL_VALUE;
+ }
+
+ aSensorData.sensor() = sensor;
+ aSensorData.accuracy() = HardwareStatusToHalAccuracy(aEvent.mStatus);
+ aSensorData.timestamp() = aEvent.mTimestamp;
+
+ if (aSensorData.sensor() == SENSOR_ORIENTATION) {
+ // Bug 938035: transfer HAL data for orientation sensor to meet W3C spec
+ // ex: HAL report alpha=90 means East but alpha=90 means West in W3C spec
+ sensorValues.AppendElement(360.0 - radToDeg(aEvent.mData.mFloat[0]));
+ sensorValues.AppendElement(-radToDeg(aEvent.mData.mFloat[1]));
+ sensorValues.AppendElement(-radToDeg(aEvent.mData.mFloat[2]));
+ } else if (aSensorData.sensor() == SENSOR_ACCELERATION) {
+ sensorValues.AppendElement(aEvent.mData.mFloat[0]);
+ sensorValues.AppendElement(aEvent.mData.mFloat[1]);
+ sensorValues.AppendElement(aEvent.mData.mFloat[2]);
+ } else if (aSensorData.sensor() == SENSOR_PROXIMITY) {
+ sensorValues.AppendElement(aEvent.mData.mFloat[0]);
+ sensorValues.AppendElement(aSensorClass.mMinValue);
+ sensorValues.AppendElement(aSensorClass.mMaxValue);
+ } else if (aSensorData.sensor() == SENSOR_LINEAR_ACCELERATION) {
+ sensorValues.AppendElement(aEvent.mData.mFloat[0]);
+ sensorValues.AppendElement(aEvent.mData.mFloat[1]);
+ sensorValues.AppendElement(aEvent.mData.mFloat[2]);
+ } else if (aSensorData.sensor() == SENSOR_GYROSCOPE) {
+ sensorValues.AppendElement(radToDeg(aEvent.mData.mFloat[0]));
+ sensorValues.AppendElement(radToDeg(aEvent.mData.mFloat[1]));
+ sensorValues.AppendElement(radToDeg(aEvent.mData.mFloat[2]));
+ } else if (aSensorData.sensor() == SENSOR_LIGHT) {
+ sensorValues.AppendElement(aEvent.mData.mFloat[0]);
+ } else if (aSensorData.sensor() == SENSOR_ROTATION_VECTOR) {
+ sensorValues.AppendElement(aEvent.mData.mFloat[0]);
+ sensorValues.AppendElement(aEvent.mData.mFloat[1]);
+ sensorValues.AppendElement(aEvent.mData.mFloat[2]);
+ sensorValues.AppendElement(aEvent.mData.mFloat[3]);
+ } else if (aSensorData.sensor() == SENSOR_GAME_ROTATION_VECTOR) {
+ sensorValues.AppendElement(aEvent.mData.mFloat[0]);
+ sensorValues.AppendElement(aEvent.mData.mFloat[1]);
+ sensorValues.AppendElement(aEvent.mData.mFloat[2]);
+ sensorValues.AppendElement(aEvent.mData.mFloat[3]);
+ }
+
+ aSensorData.values() = sensorValues;
+
+ return NS_OK;
+ }
+
+ GonkSensorsPollInterface* mPollInterface;
+ nsTArray mSensors;
+ SensorsSensorClass mClasses[SENSORS_NUM_TYPES];
+};
+
+static StaticAutoPtr sPollNotificationHandler;
+
+/**
+ * This is the notifiaction handler for the Sensors interface. If the backend
+ * crashes, we can restart it from here.
+ */
+class SensorsNotificationHandler final : public GonkSensorsNotificationHandler
+{
+public:
+ SensorsNotificationHandler(GonkSensorsInterface* aInterface)
+ : mInterface(aInterface)
+ {
+ MOZ_ASSERT(mInterface);
+
+ mInterface->SetNotificationHandler(this);
+ }
+
+ void BackendErrorNotification(bool aCrashed) override
+ {
+ // XXX: Bug 1206056: restart sensorsd
+ }
+
+private:
+ GonkSensorsInterface* mInterface;
+};
+
+static StaticAutoPtr sNotificationHandler;
+
+/**
+ * |SensorsRegisterModuleResultHandler| implements the result-handler
+ * callback for registering the Poll service and activating the first
+ * sensors. If an error occures during the process, the result handler
+ * disconnects and closes the backend.
+ */
+class SensorsRegisterModuleResultHandler final
+ : public GonkSensorsRegistryResultHandler
+{
+public:
+ SensorsRegisterModuleResultHandler(
+ uint32_t* aSensorsTypeActivated,
+ GonkSensorsInterface* aInterface)
+ : mSensorsTypeActivated(aSensorsTypeActivated)
+ , mInterface(aInterface)
+ {
+ MOZ_ASSERT(mSensorsTypeActivated);
+ MOZ_ASSERT(mInterface);
+ }
+ void OnError(SensorsError aError) override
+ {
+ GonkSensorsRegistryResultHandler::OnError(aError); // print error message
+ Disconnect(); // Registering failed, so close the connection completely
+ }
+ void RegisterModule(uint32_t aProtocolVersion) override
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(!sPollNotificationHandler);
+
+ // Init, step 3: set notification handler for poll service and vice versa
+ auto pollInterface = mInterface->GetSensorsPollInterface();
+ if (!pollInterface) {
+ Disconnect();
+ return;
+ }
+ if (NS_FAILED(pollInterface->SetProtocolVersion(aProtocolVersion))) {
+ Disconnect();
+ return;
+ }
+
+ sPollNotificationHandler =
+ new SensorsPollNotificationHandler(pollInterface);
+
+ // Init, step 4: activate sensors
+ for (int i = 0; i < SENSORS_NUM_TYPES; ++i) {
+ while (mSensorsTypeActivated[i]) {
+ sPollNotificationHandler->EnableSensorsByType(
+ static_cast(i));
+ --mSensorsTypeActivated[i];
+ }
+ }
+ }
+public:
+ void Disconnect()
+ {
+ class DisconnectResultHandler final : public GonkSensorsResultHandler
+ {
+ public:
+ void OnError(SensorsError aError)
+ {
+ GonkSensorsResultHandler::OnError(aError); // print error message
+ sNotificationHandler = nullptr;
+ }
+ void Disconnect() override
+ {
+ sNotificationHandler = nullptr;
+ }
+ };
+ mInterface->Disconnect(new DisconnectResultHandler());
+ }
+private:
+ uint32_t* mSensorsTypeActivated;
+ GonkSensorsInterface* mInterface;
+};
+
+/**
+ * |SensorsConnectResultHandler| implements the result-handler
+ * callback for starting the Sensors backend.
+ */
+class SensorsConnectResultHandler final : public GonkSensorsResultHandler
+{
+public:
+ SensorsConnectResultHandler(
+ uint32_t* aSensorsTypeActivated,
+ GonkSensorsInterface* aInterface)
+ : mSensorsTypeActivated(aSensorsTypeActivated)
+ , mInterface(aInterface)
+ {
+ MOZ_ASSERT(mSensorsTypeActivated);
+ MOZ_ASSERT(mInterface);
+ }
+ void OnError(SensorsError aError) override
+ {
+ GonkSensorsResultHandler::OnError(aError); // print error message
+ sNotificationHandler = nullptr;
+ }
+ void Connect() override
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ // Init, step 2: register poll service
+ auto registryInterface = mInterface->GetSensorsRegistryInterface();
+ if (!registryInterface) {
+ return;
+ }
+ registryInterface->RegisterModule(
+ GonkSensorsPollModule::SERVICE_ID,
+ new SensorsRegisterModuleResultHandler(mSensorsTypeActivated,
+ mInterface));
+ }
+private:
+ uint32_t* mSensorsTypeActivated;
+ GonkSensorsInterface* mInterface;
+};
+
+static uint32_t sSensorsTypeActivated[SENSORS_NUM_TYPES];
+
+static const SensorsType sSensorsType[] = {
+ [SENSOR_ORIENTATION] = SENSORS_TYPE_ORIENTATION,
+ [SENSOR_ACCELERATION] = SENSORS_TYPE_ACCELEROMETER,
+ [SENSOR_PROXIMITY] = SENSORS_TYPE_PROXIMITY,
+ [SENSOR_LINEAR_ACCELERATION] = SENSORS_TYPE_LINEAR_ACCELERATION,
+ [SENSOR_GYROSCOPE] = SENSORS_TYPE_GYROSCOPE,
+ [SENSOR_LIGHT] = SENSORS_TYPE_LIGHT,
+ [SENSOR_ROTATION_VECTOR] = SENSORS_TYPE_ROTATION_VECTOR,
+ [SENSOR_GAME_ROTATION_VECTOR] = SENSORS_TYPE_GAME_ROTATION_VECTOR
+};
+
+void
+EnableSensorNotificationsDaemon(SensorType aSensor)
+{
+ if ((aSensor < 0) ||
+ (aSensor > static_cast(MOZ_ARRAY_LENGTH(sSensorsType)))) {
+ HAL_ERR("Sensor type %d not known", aSensor);
+ return; // Unsupported sensor type
+ }
+
+ auto interface = GonkSensorsInterface::GetInstance();
+ if (!interface) {
+ return;
+ }
+
+ if (sPollNotificationHandler) {
+ // Everythings already up and running; enable sensor type.
+ sPollNotificationHandler->EnableSensorsByType(sSensorsType[aSensor]);
+ return;
+ }
+
+ ++SaturateOpUint32(sSensorsTypeActivated[sSensorsType[aSensor]]);
+
+ if (sNotificationHandler) {
+ // We are in the middle of a pending start up; nothing else to do.
+ return;
+ }
+
+ // Start up
+
+ MOZ_ASSERT(!sPollNotificationHandler);
+ MOZ_ASSERT(!sNotificationHandler);
+
+ sNotificationHandler = new SensorsNotificationHandler(interface);
+
+ // Init, step 1: connect to Sensors backend
+ interface->Connect(
+ sNotificationHandler,
+ new SensorsConnectResultHandler(sSensorsTypeActivated, interface));
+}
+
+void
+DisableSensorNotificationsDaemon(SensorType aSensor)
+{
+ if ((aSensor < 0) ||
+ (aSensor > static_cast(MOZ_ARRAY_LENGTH(sSensorsType)))) {
+ HAL_ERR("Sensor type %d not known", aSensor);
+ return; // Unsupported sensor type
+ }
+
+ if (sPollNotificationHandler) {
+ // Everthings up and running; disable sensors type
+ sPollNotificationHandler->DisableSensorsByType(sSensorsType[aSensor]);
+ return;
+ }
+
+ // We might be in the middle of a startup; decrement type's ref-counter.
+ --SaturateOpUint32(sSensorsTypeActivated[sSensorsType[aSensor]]);
+
+ // TODO: stop sensorsd if all sensors are disabled
+}
+
+//
+// Public interface
+//
+
+// TODO: Remove in-Gecko sensors code. Until all devices' base
+// images come with sensorsd installed, we have to support the
+// in-Gecko implementation as well. So we test for the existance
+// of the binary. If it's there, we use it. Otherwise we run the
+// old code.
+static bool
+HasDaemon()
+{
+ static bool tested;
+ static bool hasDaemon;
+
+ if (MOZ_UNLIKELY(!tested)) {
+ hasDaemon = !access("/system/bin/sensorsd", X_OK);
+ tested = true;
+ }
+
+ return hasDaemon;
+}
+
+void
+EnableSensorNotifications(SensorType aSensor)
+{
+ if (HasDaemon()) {
+ EnableSensorNotificationsDaemon(aSensor);
+ } else {
+ EnableSensorNotificationsInternal(aSensor);
+ }
+}
+
+void
+DisableSensorNotifications(SensorType aSensor)
+{
+ if (HasDaemon()) {
+ DisableSensorNotificationsDaemon(aSensor);
+ } else {
+ DisableSensorNotificationsInternal(aSensor);
+ }
+}
+
} // hal_impl
} // mozilla
diff --git a/hal/gonk/GonkSensorsInterface.cpp b/hal/gonk/GonkSensorsInterface.cpp
new file mode 100644
index 0000000000..c6c7658065
--- /dev/null
+++ b/hal/gonk/GonkSensorsInterface.cpp
@@ -0,0 +1,494 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "GonkSensorsInterface.h"
+#include "GonkSensorsPollInterface.h"
+#include "GonkSensorsRegistryInterface.h"
+#include "HalLog.h"
+#include
+#include
+#include
+
+namespace mozilla {
+namespace hal {
+
+using namespace mozilla::ipc;
+
+//
+// GonkSensorsResultHandler
+//
+
+void
+GonkSensorsResultHandler::OnError(SensorsError aError)
+{
+ HAL_ERR("Received error code %d", static_cast(aError));
+}
+
+void
+GonkSensorsResultHandler::Connect()
+{ }
+
+void
+GonkSensorsResultHandler::Disconnect()
+{ }
+
+GonkSensorsResultHandler::~GonkSensorsResultHandler()
+{ }
+
+//
+// GonkSensorsNotificationHandler
+//
+
+void
+GonkSensorsNotificationHandler::BackendErrorNotification(bool aCrashed)
+{
+ if (aCrashed) {
+ HAL_ERR("Sensors backend crashed");
+ } else {
+ HAL_ERR("Error in sensors backend");
+ }
+}
+
+GonkSensorsNotificationHandler::~GonkSensorsNotificationHandler()
+{ }
+
+//
+// GonkSensorsProtocol
+//
+
+class GonkSensorsProtocol final
+ : public DaemonSocketIOConsumer
+ , public GonkSensorsRegistryModule
+ , public GonkSensorsPollModule
+{
+public:
+ GonkSensorsProtocol();
+
+ void SetConnection(DaemonSocket* aConnection);
+
+ already_AddRefed FetchResultHandler(
+ const DaemonSocketPDUHeader& aHeader);
+
+ // Methods for |SensorsRegistryModule| and |SensorsPollModule|
+ //
+
+ nsresult Send(DaemonSocketPDU* aPDU,
+ DaemonSocketResultHandler* aRes) override;
+
+ // Methods for |DaemonSocketIOConsumer|
+ //
+
+ void Handle(DaemonSocketPDU& aPDU) override;
+ void StoreResultHandler(const DaemonSocketPDU& aPDU) override;
+
+private:
+ void HandleRegistrySvc(const DaemonSocketPDUHeader& aHeader,
+ DaemonSocketPDU& aPDU,
+ DaemonSocketResultHandler* aRes);
+ void HandlePollSvc(const DaemonSocketPDUHeader& aHeader,
+ DaemonSocketPDU& aPDU,
+ DaemonSocketResultHandler* aRes);
+
+ DaemonSocket* mConnection;
+ nsTArray> mResultHandlerQ;
+};
+
+GonkSensorsProtocol::GonkSensorsProtocol()
+{ }
+
+void
+GonkSensorsProtocol::SetConnection(DaemonSocket* aConnection)
+{
+ mConnection = aConnection;
+}
+
+already_AddRefed
+GonkSensorsProtocol::FetchResultHandler(const DaemonSocketPDUHeader& aHeader)
+{
+ MOZ_ASSERT(!NS_IsMainThread());
+
+ if (aHeader.mOpcode & 0x80) {
+ return nullptr; // Ignore notifications
+ }
+
+ RefPtr res = mResultHandlerQ.ElementAt(0);
+ mResultHandlerQ.RemoveElementAt(0);
+
+ return res.forget();
+}
+
+void
+GonkSensorsProtocol::HandleRegistrySvc(
+ const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
+ DaemonSocketResultHandler* aRes)
+{
+ GonkSensorsRegistryModule::HandleSvc(aHeader, aPDU, aRes);
+}
+
+void
+GonkSensorsProtocol::HandlePollSvc(
+ const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
+ DaemonSocketResultHandler* aRes)
+{
+ GonkSensorsPollModule::HandleSvc(aHeader, aPDU, aRes);
+}
+
+// |SensorsRegistryModule|, |SensorsPollModule|
+
+nsresult
+GonkSensorsProtocol::Send(DaemonSocketPDU* aPDU,
+ DaemonSocketResultHandler* aRes)
+{
+ MOZ_ASSERT(mConnection);
+ MOZ_ASSERT(aPDU);
+
+ aPDU->SetConsumer(this);
+ aPDU->SetResultHandler(aRes);
+ aPDU->UpdateHeader();
+
+ if (mConnection->GetConnectionStatus() == SOCKET_DISCONNECTED) {
+ HAL_ERR("Sensors socket is disconnected");
+ return NS_ERROR_FAILURE;
+ }
+
+ mConnection->SendSocketData(aPDU); // Forward PDU to data channel
+
+ return NS_OK;
+}
+
+// |DaemonSocketIOConsumer|
+
+void
+GonkSensorsProtocol::Handle(DaemonSocketPDU& aPDU)
+{
+ static void (GonkSensorsProtocol::* const HandleSvc[])(
+ const DaemonSocketPDUHeader&, DaemonSocketPDU&,
+ DaemonSocketResultHandler*) = {
+ [GonkSensorsRegistryModule::SERVICE_ID] =
+ &GonkSensorsProtocol::HandleRegistrySvc,
+ [GonkSensorsPollModule::SERVICE_ID] =
+ &GonkSensorsProtocol::HandlePollSvc
+ };
+
+ DaemonSocketPDUHeader header;
+
+ if (NS_FAILED(UnpackPDU(aPDU, header))) {
+ return;
+ }
+ if (!(header.mService < MOZ_ARRAY_LENGTH(HandleSvc)) ||
+ !HandleSvc[header.mService]) {
+ HAL_ERR("Sensors service %d unknown", header.mService);
+ return;
+ }
+
+ RefPtr res = FetchResultHandler(header);
+
+ (this->*(HandleSvc[header.mService]))(header, aPDU, res);
+}
+
+void
+GonkSensorsProtocol::StoreResultHandler(const DaemonSocketPDU& aPDU)
+{
+ MOZ_ASSERT(!NS_IsMainThread());
+
+ mResultHandlerQ.AppendElement(aPDU.GetResultHandler());
+}
+
+//
+// GonkSensorsInterface
+//
+
+GonkSensorsInterface*
+GonkSensorsInterface::GetInstance()
+{
+ static GonkSensorsInterface* sGonkSensorsInterface;
+
+ if (sGonkSensorsInterface) {
+ return sGonkSensorsInterface;
+ }
+
+ sGonkSensorsInterface = new GonkSensorsInterface();
+
+ return sGonkSensorsInterface;
+}
+
+void
+GonkSensorsInterface::SetNotificationHandler(
+ GonkSensorsNotificationHandler* aNotificationHandler)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ mNotificationHandler = aNotificationHandler;
+}
+
+/*
+ * The connect procedure consists of several steps.
+ *
+ * (1) Start listening for the command channel's socket connection: We
+ * do this before anything else, so that we don't miss connection
+ * requests from the Sensors daemon. This step will create a listen
+ * socket.
+ *
+ * (2) Start the Sensors daemon: When the daemon starts up it will open
+ * a socket connection to Gecko and thus create the data channel.
+ * Gecko already opened the listen socket in step (1). Step (2) ends
+ * with the creation of the data channel.
+ *
+ * (3) Signal success to the caller.
+ *
+ * If any step fails, we roll-back the procedure and signal an error to the
+ * caller.
+ */
+void
+GonkSensorsInterface::Connect(GonkSensorsNotificationHandler* aNotificationHandler,
+ GonkSensorsResultHandler* aRes)
+{
+#define BASE_SOCKET_NAME "sensorsd"
+ static unsigned long POSTFIX_LENGTH = 16;
+
+ // If we could not cleanup properly before and an old
+ // instance of the daemon is still running, we kill it
+ // here.
+ mozilla::hal::StopSystemService("sensorsd");
+
+ mNotificationHandler = aNotificationHandler;
+
+ mResultHandlerQ.AppendElement(aRes);
+
+ if (!mProtocol) {
+ mProtocol = new GonkSensorsProtocol();
+ }
+
+ if (!mListenSocket) {
+ mListenSocket = new ListenSocket(this, LISTEN_SOCKET);
+ }
+
+ // Init, step 1: Listen for data channel... */
+
+ if (!mDataSocket) {
+ mDataSocket = new DaemonSocket(mProtocol, this, DATA_SOCKET);
+ } else if (mDataSocket->GetConnectionStatus() == SOCKET_CONNECTED) {
+ // Command channel should not be open; let's close it.
+ mDataSocket->Close();
+ }
+
+ // The listen socket's name is generated with a random postfix. This
+ // avoids naming collisions if we still have a listen socket from a
+ // previously failed cleanup. It also makes it hard for malicious
+ // external programs to capture the socket name or connect before
+ // the daemon can do so. If no random postfix can be generated, we
+ // simply use the base name as-is.
+ nsresult rv = DaemonSocketConnector::CreateRandomAddressString(
+ NS_LITERAL_CSTRING(BASE_SOCKET_NAME), POSTFIX_LENGTH, mListenSocketName);
+ if (NS_FAILED(rv)) {
+ mListenSocketName.AssignLiteral(BASE_SOCKET_NAME);
+ }
+
+ rv = mListenSocket->Listen(new DaemonSocketConnector(mListenSocketName),
+ mDataSocket);
+ if (NS_FAILED(rv)) {
+ OnConnectError(DATA_SOCKET);
+ return;
+ }
+
+ // The protocol implementation needs a data channel for
+ // sending commands to the daemon. We set it here, because
+ // this is the earliest time when it's available.
+ mProtocol->SetConnection(mDataSocket);
+}
+
+/*
+ * Disconnecting is inverse to connecting.
+ *
+ * (1) Close data socket: We close the data channel and the daemon will
+ * will notice. Once we see the socket's disconnect, we continue with
+ * the cleanup.
+ *
+ * (2) Close listen socket: The listen socket is not active any longer
+ * and we simply close it.
+ *
+ * (3) Signal success to the caller.
+ *
+ * We don't have to stop the daemon explicitly. It will cleanup and quit
+ * after it noticed the closing of the data channel
+ *
+ * Rolling back half-completed cleanups is not possible. In the case of
+ * an error, we simply push forward and try to recover during the next
+ * initialization.
+ */
+void
+GonkSensorsInterface::Disconnect(GonkSensorsResultHandler* aRes)
+{
+ mNotificationHandler = nullptr;
+
+ // Cleanup, step 1: Close data channel
+ mDataSocket->Close();
+
+ mResultHandlerQ.AppendElement(aRes);
+}
+
+GonkSensorsRegistryInterface*
+GonkSensorsInterface::GetSensorsRegistryInterface()
+{
+ if (mRegistryInterface) {
+ return mRegistryInterface;
+ }
+
+ mRegistryInterface = new GonkSensorsRegistryInterface(mProtocol);
+
+ return mRegistryInterface;
+}
+
+GonkSensorsPollInterface*
+GonkSensorsInterface::GetSensorsPollInterface()
+{
+ if (mPollInterface) {
+ return mPollInterface;
+ }
+
+ mPollInterface = new GonkSensorsPollInterface(mProtocol);
+
+ return mPollInterface;
+}
+
+GonkSensorsInterface::GonkSensorsInterface()
+ : mNotificationHandler(nullptr)
+{ }
+
+GonkSensorsInterface::~GonkSensorsInterface()
+{ }
+
+void
+GonkSensorsInterface::DispatchError(GonkSensorsResultHandler* aRes,
+ SensorsError aError)
+{
+ DaemonResultRunnable1::Dispatch(
+ aRes, &GonkSensorsResultHandler::OnError,
+ ConstantInitOp1(aError));
+}
+
+void
+GonkSensorsInterface::DispatchError(
+ GonkSensorsResultHandler* aRes, nsresult aRv)
+{
+ SensorsError error;
+
+ if (NS_FAILED(Convert(aRv, error))) {
+ error = SENSORS_ERROR_FAIL;
+ }
+ DispatchError(aRes, error);
+}
+
+// |DaemonSocketConsumer|, |ListenSocketConsumer|
+
+void
+GonkSensorsInterface::OnConnectSuccess(int aIndex)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(!mResultHandlerQ.IsEmpty());
+
+ switch (aIndex) {
+ case LISTEN_SOCKET: {
+ // Init, step 2: Start Sensors daemon
+ nsCString args("-a ");
+ args.Append(mListenSocketName);
+ mozilla::hal::StartSystemService("sensorsd", args.get());
+ }
+ break;
+ case DATA_SOCKET:
+ if (!mResultHandlerQ.IsEmpty()) {
+ // Init, step 3: Signal success
+ RefPtr res = mResultHandlerQ.ElementAt(0);
+ mResultHandlerQ.RemoveElementAt(0);
+ if (res) {
+ res->Connect();
+ }
+ }
+ break;
+ }
+}
+
+void
+GonkSensorsInterface::OnConnectError(int aIndex)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(!mResultHandlerQ.IsEmpty());
+
+ switch (aIndex) {
+ case DATA_SOCKET:
+ // Stop daemon and close listen socket
+ mozilla::hal::StopSystemService("sensorsd");
+ mListenSocket->Close();
+ // fall through
+ case LISTEN_SOCKET:
+ if (!mResultHandlerQ.IsEmpty()) {
+ // Signal error to caller
+ RefPtr res = mResultHandlerQ.ElementAt(0);
+ mResultHandlerQ.RemoveElementAt(0);
+ if (res) {
+ DispatchError(res, SENSORS_ERROR_FAIL);
+ }
+ }
+ break;
+ }
+}
+
+/*
+ * Disconnects can happend
+ *
+ * (a) during startup,
+ * (b) during regular service, or
+ * (c) during shutdown.
+ *
+ * For cases (a) and (c), |mResultHandlerQ| contains an element. For
+ * case (b) |mResultHandlerQ| will be empty. This distinguishes a crash in
+ * the daemon. The following procedure to recover from crashes consists of
+ * several steps for case (b).
+ *
+ * (1) Close listen socket.
+ * (2) Wait for all sockets to be disconnected and inform caller about
+ * the crash.
+ * (3) After all resources have been cleaned up, let the caller restart
+ * the daemon.
+ */
+void
+GonkSensorsInterface::OnDisconnect(int aIndex)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ switch (aIndex) {
+ case DATA_SOCKET:
+ // Cleanup, step 2 (Recovery, step 1): Close listen socket
+ mListenSocket->Close();
+ break;
+ case LISTEN_SOCKET:
+ // Cleanup, step 3: Signal success to caller
+ if (!mResultHandlerQ.IsEmpty()) {
+ RefPtr res = mResultHandlerQ.ElementAt(0);
+ mResultHandlerQ.RemoveElementAt(0);
+ if (res) {
+ res->Disconnect();
+ }
+ }
+ break;
+ }
+
+ /* For recovery make sure all sockets disconnected, in order to avoid
+ * the remaining disconnects interfere with the restart procedure.
+ */
+ if (mNotificationHandler && mResultHandlerQ.IsEmpty()) {
+ if (mListenSocket->GetConnectionStatus() == SOCKET_DISCONNECTED &&
+ mDataSocket->GetConnectionStatus() == SOCKET_DISCONNECTED) {
+ // Recovery, step 2: Notify the caller to prepare the restart procedure.
+ mNotificationHandler->BackendErrorNotification(true);
+ mNotificationHandler = nullptr;
+ }
+ }
+}
+
+} // namespace hal
+} // namespace mozilla
diff --git a/hal/gonk/GonkSensorsInterface.h b/hal/gonk/GonkSensorsInterface.h
new file mode 100644
index 0000000000..44126ce876
--- /dev/null
+++ b/hal/gonk/GonkSensorsInterface.h
@@ -0,0 +1,190 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * The sensors interface gives you access to the low-level sensors code
+ * in a platform-independent manner. The interfaces in this file allow
+ * for starting an stopping the sensors driver. Specific functionality
+ * is implemented in sub-interfaces.
+ */
+
+#ifndef hal_gonk_GonkSensorsInterface_h
+#define hal_gonk_GonkSensorsInterface_h
+
+#include
+#include
+#include
+#include "SensorsTypes.h"
+
+namespace mozilla {
+namespace ipc {
+
+class DaemonSocket;
+class ListenSocket;
+
+}
+}
+
+namespace mozilla {
+namespace hal {
+
+class GonkSensorsPollInterface;
+class GonkSensorsProtocol;
+class GonkSensorsRegistryInterface;
+
+/**
+ * This class is the result-handler interface for the Sensors
+ * interface. Methods always run on the main thread.
+ */
+class GonkSensorsResultHandler
+ : public mozilla::ipc::DaemonSocketResultHandler
+{
+public:
+
+ /**
+ * Called if a command failed.
+ *
+ * @param aError The error code.
+ */
+ virtual void OnError(SensorsError aError);
+
+ /**
+ * The callback method for |GonkSensorsInterface::Connect|.
+ */
+ virtual void Connect();
+
+ /**
+ * The callback method for |GonkSensorsInterface::Connect|.
+ */
+ virtual void Disconnect();
+
+protected:
+ virtual ~GonkSensorsResultHandler();
+};
+
+/**
+ * This is the notification-handler interface. Implement this classes
+ * methods to handle event and notifications from the sensors daemon.
+ * All methods run on the main thread.
+ */
+class GonkSensorsNotificationHandler
+{
+public:
+
+ /**
+ * This notification is called when the backend code fails
+ * unexpectedly. Save state in the high-level code and restart
+ * the driver.
+ *
+ * @param aCrash True is the sensors driver crashed.
+ */
+ virtual void BackendErrorNotification(bool aCrashed);
+
+protected:
+ virtual ~GonkSensorsNotificationHandler();
+};
+
+/**
+ * This class implements the public interface to the Sensors functionality
+ * and driver. Use |GonkSensorsInterface::GetInstance| to retrieve an instance.
+ * All methods run on the main thread.
+ */
+class GonkSensorsInterface final
+ : public mozilla::ipc::DaemonSocketConsumer
+ , public mozilla::ipc::ListenSocketConsumer
+{
+public:
+ /**
+ * Returns an instance of the Sensors backend. This code can return
+ * |nullptr| if no Sensors backend is available.
+ *
+ * @return An instance of |GonkSensorsInterface|.
+ */
+ static GonkSensorsInterface* GetInstance();
+
+ /**
+ * This method sets the notification handler for sensor notifications. Call
+ * this method immediately after retreiving an instance of the class, or you
+ * won't be able able to receive notifications. You may not free the handler
+ * class while the Sensors backend is connected.
+ *
+ * @param aNotificationHandler An instance of a notification handler.
+ */
+ void SetNotificationHandler(
+ GonkSensorsNotificationHandler* aNotificationHandler);
+
+ /**
+ * This method starts the Sensors backend and establishes ad connection
+ * with Gecko. This is a multi-step process and errors are signalled by
+ * |GonkSensorsNotificationHandler::BackendErrorNotification|. If you see
+ * this notification before the connection has been established, it's
+ * certainly best to assume the Sensors backend to be not evailable.
+ *
+ * @param aRes The result handler.
+ */
+ void Connect(GonkSensorsNotificationHandler* aNotificationHandler,
+ GonkSensorsResultHandler* aRes);
+
+ /**
+ * This method disconnects Gecko from the Sensors backend and frees
+ * the backend's resources. This will invalidate all interfaces and
+ * state. Don't use any sensors functionality without reconnecting
+ * first.
+ *
+ * @param aRes The result handler.
+ */
+ void Disconnect(GonkSensorsResultHandler* aRes);
+
+ /**
+ * Returns the Registry interface for the connected Sensors backend.
+ *
+ * @return An instance of the Sensors Registry interface.
+ */
+ GonkSensorsRegistryInterface* GetSensorsRegistryInterface();
+
+ /**
+ * Returns the Poll interface for the connected Sensors backend.
+ *
+ * @return An instance of the Sensors Poll interface.
+ */
+ GonkSensorsPollInterface* GetSensorsPollInterface();
+
+private:
+ enum Channel {
+ LISTEN_SOCKET,
+ DATA_SOCKET
+ };
+
+ GonkSensorsInterface();
+ ~GonkSensorsInterface();
+
+ void DispatchError(GonkSensorsResultHandler* aRes, SensorsError aError);
+ void DispatchError(GonkSensorsResultHandler* aRes, nsresult aRv);
+
+ // Methods for |DaemonSocketConsumer| and |ListenSocketConsumer|
+ //
+
+ void OnConnectSuccess(int aIndex) override;
+ void OnConnectError(int aIndex) override;
+ void OnDisconnect(int aIndex) override;
+
+ nsCString mListenSocketName;
+ RefPtr mListenSocket;
+ RefPtr mDataSocket;
+ nsAutoPtr mProtocol;
+
+ nsTArray > mResultHandlerQ;
+
+ GonkSensorsNotificationHandler* mNotificationHandler;
+
+ nsAutoPtr mRegistryInterface;
+ nsAutoPtr mPollInterface;
+};
+
+} // namespace hal
+} // namespace mozilla
+
+#endif // hal_gonk_GonkSensorsInterface_h
diff --git a/hal/gonk/GonkSensorsPollInterface.cpp b/hal/gonk/GonkSensorsPollInterface.cpp
new file mode 100644
index 0000000000..010deb656a
--- /dev/null
+++ b/hal/gonk/GonkSensorsPollInterface.cpp
@@ -0,0 +1,430 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "GonkSensorsPollInterface.h"
+#include "HalLog.h"
+
+namespace mozilla {
+namespace hal {
+
+using namespace mozilla::ipc;
+
+//
+// GonkSensorsPollResultHandler
+//
+
+void
+GonkSensorsPollResultHandler::OnError(SensorsError aError)
+{
+ HAL_ERR("Received error code %d", static_cast(aError));
+}
+
+void
+GonkSensorsPollResultHandler::EnableSensor()
+{ }
+
+void
+GonkSensorsPollResultHandler::DisableSensor()
+{ }
+
+void
+GonkSensorsPollResultHandler::SetPeriod()
+{ }
+
+GonkSensorsPollResultHandler::~GonkSensorsPollResultHandler()
+{ }
+
+//
+// GonkSensorsPollNotificationHandler
+//
+
+void
+GonkSensorsPollNotificationHandler::ErrorNotification(SensorsError aError)
+{
+ HAL_ERR("Received error code %d", static_cast(aError));
+}
+
+void
+GonkSensorsPollNotificationHandler::SensorDetectedNotification(
+ int32_t aId,
+ SensorsType aType,
+ float aRange,
+ float aResolution,
+ float aPower,
+ int32_t aMinPeriod,
+ int32_t aMaxPeriod,
+ SensorsTriggerMode aTriggerMode,
+ SensorsDeliveryMode aDeliveryMode)
+{ }
+
+void
+GonkSensorsPollNotificationHandler::SensorLostNotification(int32_t aId)
+{ }
+
+void
+GonkSensorsPollNotificationHandler::EventNotification(int32_t aId,
+ const SensorsEvent& aEvent)
+{ }
+
+GonkSensorsPollNotificationHandler::~GonkSensorsPollNotificationHandler()
+{ }
+
+//
+// GonkSensorsPollModule
+//
+
+GonkSensorsPollModule::GonkSensorsPollModule()
+ : mProtocolVersion(0)
+{ }
+
+GonkSensorsPollModule::~GonkSensorsPollModule()
+{ }
+
+nsresult
+GonkSensorsPollModule::SetProtocolVersion(unsigned long aProtocolVersion)
+{
+ if ((aProtocolVersion < MIN_PROTOCOL_VERSION) ||
+ (aProtocolVersion > MAX_PROTOCOL_VERSION)) {
+ HAL_ERR("Sensors Poll protocol version %lu not supported",
+ aProtocolVersion);
+ return NS_ERROR_ILLEGAL_VALUE;
+ }
+ mProtocolVersion = aProtocolVersion;
+ return NS_OK;
+}
+
+void
+GonkSensorsPollModule::HandleSvc(const DaemonSocketPDUHeader& aHeader,
+ DaemonSocketPDU& aPDU,
+ DaemonSocketResultHandler* aRes)
+{
+ static void (GonkSensorsPollModule::* const HandleOp[])(
+ const DaemonSocketPDUHeader&, DaemonSocketPDU&,
+ DaemonSocketResultHandler*) = {
+ [0] = &GonkSensorsPollModule::HandleRsp,
+ [1] = &GonkSensorsPollModule::HandleNtf
+ };
+
+ MOZ_ASSERT(!NS_IsMainThread()); // I/O thread
+
+ // Negate twice to map bit to 0/1
+ unsigned long isNtf = !!(aHeader.mOpcode & 0x80);
+
+ (this->*(HandleOp[isNtf]))(aHeader, aPDU, aRes);
+}
+
+// Commands
+//
+
+nsresult
+GonkSensorsPollModule::EnableSensorCmd(int32_t aId, GonkSensorsPollResultHandler* aRes)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ nsAutoPtr pdu(
+ new DaemonSocketPDU(SERVICE_ID, OPCODE_ENABLE_SENSOR, 0));
+
+ nsresult rv = PackPDU(aId, *pdu);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = Send(pdu, aRes);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ Unused << pdu.forget();
+ return NS_OK;
+}
+
+nsresult
+GonkSensorsPollModule::DisableSensorCmd(int32_t aId, GonkSensorsPollResultHandler* aRes)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ nsAutoPtr pdu(
+ new DaemonSocketPDU(SERVICE_ID, OPCODE_DISABLE_SENSOR, 0));
+
+ nsresult rv = PackPDU(aId, *pdu);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = Send(pdu, aRes);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ Unused << pdu.forget();
+ return NS_OK;
+}
+
+nsresult
+GonkSensorsPollModule::SetPeriodCmd(int32_t aId, uint64_t aPeriod,
+ GonkSensorsPollResultHandler* aRes)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ nsAutoPtr pdu(
+ new DaemonSocketPDU(SERVICE_ID, OPCODE_SET_PERIOD, 0));
+
+ nsresult rv = PackPDU(aId, *pdu);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aPeriod, *pdu);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = Send(pdu, aRes);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ Unused << pdu.forget();
+ return NS_OK;
+}
+
+// Responses
+//
+
+void
+GonkSensorsPollModule::ErrorRsp(
+ const DaemonSocketPDUHeader& aHeader,
+ DaemonSocketPDU& aPDU, GonkSensorsPollResultHandler* aRes)
+{
+ ErrorRunnable::Dispatch(
+ aRes, &GonkSensorsPollResultHandler::OnError, UnpackPDUInitOp(aPDU));
+}
+
+void
+GonkSensorsPollModule::EnableSensorRsp(
+ const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
+ GonkSensorsPollResultHandler* aRes)
+{
+ ResultRunnable::Dispatch(
+ aRes, &GonkSensorsPollResultHandler::EnableSensor, UnpackPDUInitOp(aPDU));
+}
+
+void
+GonkSensorsPollModule::DisableSensorRsp(
+ const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
+ GonkSensorsPollResultHandler* aRes)
+{
+ ResultRunnable::Dispatch(
+ aRes, &GonkSensorsPollResultHandler::DisableSensor, UnpackPDUInitOp(aPDU));
+}
+
+void
+GonkSensorsPollModule::SetPeriodRsp(
+ const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
+ GonkSensorsPollResultHandler* aRes)
+{
+ ResultRunnable::Dispatch(
+ aRes, &GonkSensorsPollResultHandler::SetPeriod, UnpackPDUInitOp(aPDU));
+}
+
+void
+GonkSensorsPollModule::HandleRsp(
+ const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
+ DaemonSocketResultHandler* aRes)
+{
+ static void (GonkSensorsPollModule::* const sHandleRsp[])(
+ const DaemonSocketPDUHeader&, DaemonSocketPDU&,
+ GonkSensorsPollResultHandler*) = {
+ [OPCODE_ERROR] = &GonkSensorsPollModule::ErrorRsp,
+ [OPCODE_ENABLE_SENSOR] = &GonkSensorsPollModule::EnableSensorRsp,
+ [OPCODE_DISABLE_SENSOR] = &GonkSensorsPollModule::DisableSensorRsp,
+ [OPCODE_SET_PERIOD] = &GonkSensorsPollModule::SetPeriodRsp,
+ };
+
+ MOZ_ASSERT(!NS_IsMainThread()); // I/O thread
+
+ if (!(aHeader.mOpcode < MOZ_ARRAY_LENGTH(sHandleRsp)) ||
+ !sHandleRsp[aHeader.mOpcode]) {
+ HAL_ERR("Sensors poll response opcode %d unknown", aHeader.mOpcode);
+ return;
+ }
+
+ RefPtr res =
+ static_cast(aRes);
+
+ if (!res) {
+ return; // Return early if no result handler has been set for response
+ }
+
+ (this->*(sHandleRsp[aHeader.mOpcode]))(aHeader, aPDU, res);
+}
+
+// Notifications
+//
+
+// Returns the current notification handler to a notification runnable
+class GonkSensorsPollModule::NotificationHandlerWrapper final
+{
+public:
+ typedef GonkSensorsPollNotificationHandler ObjectType;
+
+ static ObjectType* GetInstance()
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ return sNotificationHandler;
+ }
+
+ static GonkSensorsPollNotificationHandler* sNotificationHandler;
+};
+
+GonkSensorsPollNotificationHandler*
+ GonkSensorsPollModule::NotificationHandlerWrapper::sNotificationHandler;
+
+void
+GonkSensorsPollModule::ErrorNtf(
+ const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
+{
+ ErrorNotification::Dispatch(
+ &GonkSensorsPollNotificationHandler::ErrorNotification,
+ UnpackPDUInitOp(aPDU));
+}
+
+void
+GonkSensorsPollModule::SensorDetectedNtf(
+ const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
+{
+ SensorDetectedNotification::Dispatch(
+ &GonkSensorsPollNotificationHandler::SensorDetectedNotification,
+ UnpackPDUInitOp(aPDU));
+}
+
+void
+GonkSensorsPollModule::SensorLostNtf(
+ const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
+{
+ SensorLostNotification::Dispatch(
+ &GonkSensorsPollNotificationHandler::SensorLostNotification,
+ UnpackPDUInitOp(aPDU));
+}
+
+void
+GonkSensorsPollModule::EventNtf(
+ const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
+{
+ EventNotification::Dispatch(
+ &GonkSensorsPollNotificationHandler::EventNotification,
+ UnpackPDUInitOp(aPDU));
+}
+
+void
+GonkSensorsPollModule::HandleNtf(
+ const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
+ DaemonSocketResultHandler* aRes)
+{
+ static void (GonkSensorsPollModule::* const sHandleNtf[])(
+ const DaemonSocketPDUHeader&, DaemonSocketPDU&) = {
+ [0] = &GonkSensorsPollModule::ErrorNtf,
+ [1] = &GonkSensorsPollModule::SensorDetectedNtf,
+ [2] = &GonkSensorsPollModule::SensorLostNtf,
+ [3] = &GonkSensorsPollModule::EventNtf
+ };
+
+ MOZ_ASSERT(!NS_IsMainThread());
+
+ uint8_t index = aHeader.mOpcode - 0x80;
+
+ if (!(index < MOZ_ARRAY_LENGTH(sHandleNtf)) || !sHandleNtf[index]) {
+ HAL_ERR("Sensors poll notification opcode %d unknown", aHeader.mOpcode);
+ return;
+ }
+
+ (this->*(sHandleNtf[index]))(aHeader, aPDU);
+}
+
+//
+// GonkSensorsPollInterface
+//
+
+GonkSensorsPollInterface::GonkSensorsPollInterface(
+ GonkSensorsPollModule* aModule)
+ : mModule(aModule)
+{ }
+
+GonkSensorsPollInterface::~GonkSensorsPollInterface()
+{ }
+
+void
+GonkSensorsPollInterface::SetNotificationHandler(
+ GonkSensorsPollNotificationHandler* aNotificationHandler)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ GonkSensorsPollModule::NotificationHandlerWrapper::sNotificationHandler =
+ aNotificationHandler;
+}
+
+nsresult
+GonkSensorsPollInterface::SetProtocolVersion(unsigned long aProtocolVersion)
+{
+ MOZ_ASSERT(mModule);
+
+ return mModule->SetProtocolVersion(aProtocolVersion);
+}
+
+void
+GonkSensorsPollInterface::EnableSensor(int32_t aId,
+ GonkSensorsPollResultHandler* aRes)
+{
+ MOZ_ASSERT(mModule);
+
+ nsresult rv = mModule->EnableSensorCmd(aId, aRes);
+ if (NS_FAILED(rv)) {
+ DispatchError(aRes, rv);
+ }
+}
+
+void
+GonkSensorsPollInterface::DisableSensor(int32_t aId,
+ GonkSensorsPollResultHandler* aRes)
+{
+ MOZ_ASSERT(mModule);
+
+ nsresult rv = mModule->DisableSensorCmd(aId, aRes);
+ if (NS_FAILED(rv)) {
+ DispatchError(aRes, rv);
+ }
+}
+
+void
+GonkSensorsPollInterface::SetPeriod(int32_t aId, uint64_t aPeriod,
+ GonkSensorsPollResultHandler* aRes)
+{
+ MOZ_ASSERT(mModule);
+
+ nsresult rv = mModule->SetPeriodCmd(aId, aPeriod, aRes);
+ if (NS_FAILED(rv)) {
+ DispatchError(aRes, rv);
+ }
+}
+
+void
+GonkSensorsPollInterface::DispatchError(
+ GonkSensorsPollResultHandler* aRes, SensorsError aError)
+{
+ DaemonResultRunnable1::Dispatch(
+ aRes, &GonkSensorsPollResultHandler::OnError,
+ ConstantInitOp1(aError));
+}
+
+void
+GonkSensorsPollInterface::DispatchError(
+ GonkSensorsPollResultHandler* aRes, nsresult aRv)
+{
+ SensorsError error;
+
+ if (NS_FAILED(Convert(aRv, error))) {
+ error = SENSORS_ERROR_FAIL;
+ }
+ DispatchError(aRes, error);
+}
+
+} // namespace hal
+} // namespace mozilla
diff --git a/hal/gonk/GonkSensorsPollInterface.h b/hal/gonk/GonkSensorsPollInterface.h
new file mode 100644
index 0000000000..d25fed4f3e
--- /dev/null
+++ b/hal/gonk/GonkSensorsPollInterface.h
@@ -0,0 +1,343 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * The poll interface gives yo access to the Sensors daemon's Poll service,
+ * which handles sensors. The poll service will inform you when sensors are
+ * detected or removed from the system. You can activate (or deactivate)
+ * existing sensors and poll will deliver the sensors' events.
+ *
+ * All public methods and callback methods run on the main thread.
+ */
+
+#ifndef hal_gonk_GonkSensorsPollInterface_h
+#define hal_gonk_GonkSensorsPollInterface_h
+
+#include
+#include
+#include "SensorsTypes.h"
+
+namespace mozilla {
+namespace ipc {
+
+class DaemonSocketPDU;
+class DaemonSocketPDUHeader;
+
+}
+}
+
+namespace mozilla {
+namespace hal {
+
+class SensorsInterface;
+
+using mozilla::ipc::DaemonSocketPDU;
+using mozilla::ipc::DaemonSocketPDUHeader;
+using mozilla::ipc::DaemonSocketResultHandler;
+
+/**
+ * This class is the result-handler interface for the Sensors
+ * Poll interface. Methods always run on the main thread.
+ */
+class GonkSensorsPollResultHandler : public DaemonSocketResultHandler
+{
+public:
+
+ /**
+ * Called if a poll command failed.
+ *
+ * @param aError The error code.
+ */
+ virtual void OnError(SensorsError aError);
+
+ /**
+ * The callback method for |GonkSensorsPollInterface::EnableSensor|.
+ */
+ virtual void EnableSensor();
+
+ /**
+ * The callback method for |GonkSensorsPollInterface::DisableSensor|.
+ */
+ virtual void DisableSensor();
+
+ /**
+ * The callback method for |GonkSensorsPollInterface::SetPeriod|.
+ */
+ virtual void SetPeriod();
+
+protected:
+ virtual ~GonkSensorsPollResultHandler();
+};
+
+/**
+ * This is the notification-handler interface. Implement this classes
+ * methods to handle event and notifications from the sensors daemon.
+ */
+class GonkSensorsPollNotificationHandler
+{
+public:
+
+ /**
+ * The notification handler for errors. You'll receive this call if
+ * there's been a critical error in the daemon. Either try to handle
+ * the error, or restart the daemon.
+ *
+ * @param aError The error code.
+ */
+ virtual void ErrorNotification(SensorsError aError);
+
+ /**
+ * This methods gets call when a new sensor has been detected.
+ *
+ * @param aId The sensor's id.
+ * @param aType The sensor's type.
+ * @param aRange The sensor's maximum value.
+ * @param aResolution The minimum difference between two consecutive values.
+ * @param aPower The sensor's power consumption (in mA).
+ * @param aMinPeriod The minimum time between two events (in ns).
+ * @param aMaxPeriod The maximum time between two events (in ns).
+ * @param aTriggerMode The sensor's mode for triggering events.
+ * @param aDeliveryMode The sensor's urgency for event delivery.
+ */
+ virtual void SensorDetectedNotification(int32_t aId, SensorsType aType,
+ float aRange, float aResolution,
+ float aPower, int32_t aMinPeriod,
+ int32_t aMaxPeriod,
+ SensorsTriggerMode aTriggerMode,
+ SensorsDeliveryMode aDeliveryMode);
+
+ /**
+ * This methods gets call when an existing sensor has been removed.
+ *
+ * @param aId The sensor's id.
+ */
+ virtual void SensorLostNotification(int32_t aId);
+
+ /**
+ * This is the callback methods for sensor events. Only activated sensors
+ * generate events. All sensors are disabled by default. The actual data
+ * of the event depends on the sensor type.
+ *
+ * @param aId The sensor's id.
+ * @param aEvent The event's data.
+ */
+ virtual void EventNotification(int32_t aId, const SensorsEvent& aEvent);
+
+protected:
+ virtual ~GonkSensorsPollNotificationHandler();
+};
+
+/**
+ * This is the module class for the Sensors poll component. It handles PDU
+ * packing and unpacking. Methods are either executed on the main thread or
+ * the I/O thread.
+ *
+ * This is an internal class, use |GonkSensorsPollInterface| instead.
+ */
+class GonkSensorsPollModule
+{
+public:
+ class NotificationHandlerWrapper;
+
+ enum {
+ SERVICE_ID = 0x01
+ };
+
+ enum {
+ OPCODE_ERROR = 0x00,
+ OPCODE_ENABLE_SENSOR = 0x01,
+ OPCODE_DISABLE_SENSOR = 0x02,
+ OPCODE_SET_PERIOD = 0x03
+ };
+
+ enum {
+ MIN_PROTOCOL_VERSION = 1,
+ MAX_PROTOCOL_VERSION = 1
+ };
+
+ virtual nsresult Send(DaemonSocketPDU* aPDU,
+ DaemonSocketResultHandler* aRes) = 0;
+
+ nsresult SetProtocolVersion(unsigned long aProtocolVersion);
+
+ //
+ // Commands
+ //
+
+ nsresult EnableSensorCmd(int32_t aId,
+ GonkSensorsPollResultHandler* aRes);
+
+ nsresult DisableSensorCmd(int32_t aId,
+ GonkSensorsPollResultHandler* aRes);
+
+ nsresult SetPeriodCmd(int32_t aId, uint64_t aPeriod,
+ GonkSensorsPollResultHandler* aRes);
+
+protected:
+ GonkSensorsPollModule();
+ virtual ~GonkSensorsPollModule();
+
+ void HandleSvc(const DaemonSocketPDUHeader& aHeader,
+ DaemonSocketPDU& aPDU,
+ DaemonSocketResultHandler* aRes);
+
+private:
+
+ //
+ // Responses
+ //
+
+ typedef mozilla::ipc::DaemonResultRunnable0<
+ GonkSensorsPollResultHandler, void>
+ ResultRunnable;
+
+ typedef mozilla::ipc::DaemonResultRunnable1<
+ GonkSensorsPollResultHandler, void, SensorsError, SensorsError>
+ ErrorRunnable;
+
+ void ErrorRsp(const DaemonSocketPDUHeader& aHeader,
+ DaemonSocketPDU& aPDU,
+ GonkSensorsPollResultHandler* aRes);
+
+ void EnableSensorRsp(const DaemonSocketPDUHeader& aHeader,
+ DaemonSocketPDU& aPDU,
+ GonkSensorsPollResultHandler* aRes);
+
+ void DisableSensorRsp(const DaemonSocketPDUHeader& aHeader,
+ DaemonSocketPDU& aPDU,
+ GonkSensorsPollResultHandler* aRes);
+
+ void SetPeriodRsp(const DaemonSocketPDUHeader& aHeader,
+ DaemonSocketPDU& aPDU,
+ GonkSensorsPollResultHandler* aRes);
+
+ void HandleRsp(const DaemonSocketPDUHeader& aHeader,
+ DaemonSocketPDU& aPDU,
+ DaemonSocketResultHandler* aRes);
+
+ //
+ // Notifications
+ //
+
+ typedef mozilla::ipc::DaemonNotificationRunnable1<
+ NotificationHandlerWrapper, void, SensorsError>
+ ErrorNotification;
+
+ typedef mozilla::ipc::DaemonNotificationRunnable9<
+ NotificationHandlerWrapper, void, int32_t, SensorsType,
+ float, float, float, int32_t, int32_t, SensorsTriggerMode,
+ SensorsDeliveryMode>
+ SensorDetectedNotification;
+
+ typedef mozilla::ipc::DaemonNotificationRunnable1<
+ NotificationHandlerWrapper, void, int32_t>
+ SensorLostNotification;
+
+ typedef mozilla::ipc::DaemonNotificationRunnable2<
+ NotificationHandlerWrapper, void, int32_t, SensorsEvent, int32_t,
+ const SensorsEvent&>
+ EventNotification;
+
+ class SensorDetectedInitOp;
+ class SensorLostInitOp;
+ class EventInitOp;
+
+ void ErrorNtf(const DaemonSocketPDUHeader& aHeader,
+ DaemonSocketPDU& aPDU);
+
+ void SensorDetectedNtf(const DaemonSocketPDUHeader& aHeader,
+ DaemonSocketPDU& aPDU);
+
+ void SensorLostNtf(const DaemonSocketPDUHeader& aHeader,
+ DaemonSocketPDU& aPDU);
+
+ void EventNtf(const DaemonSocketPDUHeader& aHeader,
+ DaemonSocketPDU& aPDU);
+
+ void HandleNtf(const DaemonSocketPDUHeader& aHeader,
+ DaemonSocketPDU& aPDU,
+ DaemonSocketResultHandler* aRes);
+
+private:
+ unsigned long mProtocolVersion;
+};
+
+/**
+ * This class implements the public interface to the Sensors poll
+ * component. Use |SensorsInterface::GetPollInterface| to retrieve
+ * an instance. All methods run on the main thread.
+ */
+class GonkSensorsPollInterface final
+{
+public:
+ friend class GonkSensorsInterface;
+
+ /**
+ * This method sets the notification handler for poll notifications. Call
+ * this method immediately after registering the module. Otherwise you won't
+ * be able able to receive poll notifications. You may not free the handler
+ * class while the poll component is regsitered.
+ *
+ * @param aNotificationHandler An instance of a poll notification handler.
+ */
+ void SetNotificationHandler(
+ GonkSensorsPollNotificationHandler* aNotificationHandler);
+
+ /**
+ * This method sets the protocol version. You should set it to the
+ * value that has been returned from the backend when registering the
+ * Poll service. You cannot send or receive messages before setting
+ * the protocol version.
+ *
+ * @param aProtocolVersion
+ * @return NS_OK for supported versions, or an XPCOM error code otherwise.
+ */
+ nsresult SetProtocolVersion(unsigned long aProtocolVersion);
+
+ /**
+ * Enables an existing sensor. The sensor id will have been delivered in
+ * a SensorDetectedNotification.
+ *
+ * @param aId The sensor's id.
+ * @param aRes The result handler.
+ */
+ void EnableSensor(int32_t aId, GonkSensorsPollResultHandler* aRes);
+
+ /**
+ * Disables an existing sensor. The sensor id will have been delivered in
+ * a SensorDetectedNotification.
+ *
+ * @param aId The sensor's id.
+ * @param aRes The result handler.
+ */
+ void DisableSensor(int32_t aId, GonkSensorsPollResultHandler* aRes);
+
+ /**
+ * Sets the period for a sensor. The sensor id will have been delivered in
+ * a SensorDetectedNotification. The value for the period should be between
+ * the sensor's minimum and maximum period.
+ *
+ * @param aId The sensor's id.
+ * @param aPeriod The sensor's new period.
+ * @param aRes The result handler.
+ */
+ void SetPeriod(int32_t aId, uint64_t aPeriod, GonkSensorsPollResultHandler* aRes);
+
+ ~GonkSensorsPollInterface();
+
+private:
+ GonkSensorsPollInterface(GonkSensorsPollModule* aModule);
+
+ void DispatchError(GonkSensorsPollResultHandler* aRes, SensorsError aError);
+ void DispatchError(GonkSensorsPollResultHandler* aRes, nsresult aRv);
+
+ GonkSensorsPollModule* mModule;
+};
+
+} // hal
+} // namespace mozilla
+
+#endif // hal_gonk_GonkSensorsPollInterface_h
diff --git a/hal/gonk/GonkSensorsRegistryInterface.cpp b/hal/gonk/GonkSensorsRegistryInterface.cpp
new file mode 100644
index 0000000000..0fc318fe2a
--- /dev/null
+++ b/hal/gonk/GonkSensorsRegistryInterface.cpp
@@ -0,0 +1,212 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "GonkSensorsRegistryInterface.h"
+#include "GonkSensorsHelpers.h"
+#include "HalLog.h"
+
+namespace mozilla {
+namespace hal {
+
+using namespace mozilla::ipc;
+
+//
+// GonkSensorsRegistryResultHandler
+//
+
+void
+GonkSensorsRegistryResultHandler::OnError(SensorsError aError)
+{
+ HAL_ERR("Received error code %d", static_cast(aError));
+}
+
+void
+GonkSensorsRegistryResultHandler::RegisterModule(uint32_t aProtocolVersion)
+{ }
+
+void
+GonkSensorsRegistryResultHandler::UnregisterModule()
+{ }
+
+GonkSensorsRegistryResultHandler::~GonkSensorsRegistryResultHandler()
+{ }
+
+//
+// GonkSensorsRegistryModule
+//
+
+GonkSensorsRegistryModule::~GonkSensorsRegistryModule()
+{ }
+
+void
+GonkSensorsRegistryModule::HandleSvc(const DaemonSocketPDUHeader& aHeader,
+ DaemonSocketPDU& aPDU,
+ DaemonSocketResultHandler* aRes)
+{
+ static void (GonkSensorsRegistryModule::* const HandleRsp[])(
+ const DaemonSocketPDUHeader&,
+ DaemonSocketPDU&,
+ GonkSensorsRegistryResultHandler*) = {
+ [OPCODE_ERROR] = &GonkSensorsRegistryModule::ErrorRsp,
+ [OPCODE_REGISTER_MODULE] = &GonkSensorsRegistryModule::RegisterModuleRsp,
+ [OPCODE_UNREGISTER_MODULE] = &GonkSensorsRegistryModule::UnregisterModuleRsp
+ };
+
+ if ((aHeader.mOpcode >= MOZ_ARRAY_LENGTH(HandleRsp)) ||
+ !HandleRsp[aHeader.mOpcode]) {
+ HAL_ERR("Sensors registry response opcode %d unknown", aHeader.mOpcode);
+ return;
+ }
+
+ RefPtr res =
+ static_cast(aRes);
+
+ if (!res) {
+ return; // Return early if no result handler has been set
+ }
+
+ (this->*(HandleRsp[aHeader.mOpcode]))(aHeader, aPDU, res);
+}
+
+// Commands
+//
+
+nsresult
+GonkSensorsRegistryModule::RegisterModuleCmd(
+ uint8_t aId, GonkSensorsRegistryResultHandler* aRes)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ nsAutoPtr pdu(
+ new DaemonSocketPDU(SERVICE_ID, OPCODE_REGISTER_MODULE, 0));
+
+ nsresult rv = PackPDU(aId, *pdu);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = Send(pdu, aRes);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ Unused << pdu.forget();
+ return NS_OK;
+}
+
+nsresult
+GonkSensorsRegistryModule::UnregisterModuleCmd(
+ uint8_t aId, GonkSensorsRegistryResultHandler* aRes)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ nsAutoPtr pdu(
+ new DaemonSocketPDU(SERVICE_ID, OPCODE_UNREGISTER_MODULE, 0));
+
+ nsresult rv = PackPDU(aId, *pdu);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = Send(pdu, aRes);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ Unused << pdu.forget();
+ return NS_OK;
+}
+
+// Responses
+//
+
+void
+GonkSensorsRegistryModule::ErrorRsp(
+ const DaemonSocketPDUHeader& aHeader,
+ DaemonSocketPDU& aPDU, GonkSensorsRegistryResultHandler* aRes)
+{
+ ErrorRunnable::Dispatch(
+ aRes, &GonkSensorsRegistryResultHandler::OnError, UnpackPDUInitOp(aPDU));
+}
+
+void
+GonkSensorsRegistryModule::RegisterModuleRsp(
+ const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
+ GonkSensorsRegistryResultHandler* aRes)
+{
+ Uint32ResultRunnable::Dispatch(
+ aRes,
+ &GonkSensorsRegistryResultHandler::RegisterModule,
+ UnpackPDUInitOp(aPDU));
+}
+
+void
+GonkSensorsRegistryModule::UnregisterModuleRsp(
+ const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
+ GonkSensorsRegistryResultHandler* aRes)
+{
+ ResultRunnable::Dispatch(
+ aRes,
+ &GonkSensorsRegistryResultHandler::UnregisterModule,
+ UnpackPDUInitOp(aPDU));
+}
+
+//
+// GonkSensorsRegistryInterface
+//
+
+GonkSensorsRegistryInterface::GonkSensorsRegistryInterface(
+ GonkSensorsRegistryModule* aModule)
+ : mModule(aModule)
+{ }
+
+GonkSensorsRegistryInterface::~GonkSensorsRegistryInterface()
+{ }
+
+void
+GonkSensorsRegistryInterface::RegisterModule(
+ uint8_t aId, GonkSensorsRegistryResultHandler* aRes)
+{
+ MOZ_ASSERT(mModule);
+
+ nsresult rv = mModule->RegisterModuleCmd(aId, aRes);
+ if (NS_FAILED(rv)) {
+ DispatchError(aRes, rv);
+ }
+}
+
+void
+GonkSensorsRegistryInterface::UnregisterModule(
+ uint8_t aId, GonkSensorsRegistryResultHandler* aRes)
+{
+ MOZ_ASSERT(mModule);
+
+ nsresult rv = mModule->UnregisterModuleCmd(aId, aRes);
+ if (NS_FAILED(rv)) {
+ DispatchError(aRes, rv);
+ }
+}
+
+void
+GonkSensorsRegistryInterface::DispatchError(
+ GonkSensorsRegistryResultHandler* aRes, SensorsError aError)
+{
+ DaemonResultRunnable1::Dispatch(
+ aRes, &GonkSensorsRegistryResultHandler::OnError,
+ ConstantInitOp1(aError));
+}
+
+void
+GonkSensorsRegistryInterface::DispatchError(
+ GonkSensorsRegistryResultHandler* aRes, nsresult aRv)
+{
+ SensorsError error;
+
+ if (NS_FAILED(Convert(aRv, error))) {
+ error = SENSORS_ERROR_FAIL;
+ }
+ DispatchError(aRes, error);
+}
+
+} // namespace hal
+} // namespace mozilla
diff --git a/hal/gonk/GonkSensorsRegistryInterface.h b/hal/gonk/GonkSensorsRegistryInterface.h
new file mode 100644
index 0000000000..e7d64cb1d8
--- /dev/null
+++ b/hal/gonk/GonkSensorsRegistryInterface.h
@@ -0,0 +1,185 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * The registry interface gives yo access to the Sensors daemon's Registry
+ * service. The purpose of the service is to register and setup all other
+ * services, and make them available.
+ *
+ * All public methods and callback methods run on the main thread.
+ */
+
+#ifndef hal_gonk_GonkSensorsRegistryInterface_h
+#define hal_gonk_GonkSensorsRegistryInterface_h
+
+#include
+#include
+#include "SensorsTypes.h"
+
+namespace mozilla {
+namespace ipc {
+
+class DaemonSocketPDU;
+class DaemonSocketPDUHeader;
+
+}
+}
+
+namespace mozilla {
+namespace hal {
+
+class SensorsInterface;
+
+using mozilla::ipc::DaemonSocketPDU;
+using mozilla::ipc::DaemonSocketPDUHeader;
+using mozilla::ipc::DaemonSocketResultHandler;
+
+/**
+ * This class is the result-handler interface for the Sensors
+ * Registry interface. Methods always run on the main thread.
+ */
+class GonkSensorsRegistryResultHandler : public DaemonSocketResultHandler
+{
+public:
+
+ /**
+ * Called if a registry command failed.
+ *
+ * @param aError The error code.
+ */
+ virtual void OnError(SensorsError aError);
+
+ /**
+ * The callback method for |GonkSensorsRegistryInterface::RegisterModule|.
+ *
+ * @param aProtocolVersion The daemon's protocol version. Make sure it's
+ * compatible with Gecko's implementation.
+ */
+ virtual void RegisterModule(uint32_t aProtocolVersion);
+
+ /**
+ * The callback method for |SensorsRegsitryInterface::UnregisterModule|.
+ */
+ virtual void UnregisterModule();
+
+protected:
+ virtual ~GonkSensorsRegistryResultHandler();
+};
+
+/**
+ * This is the module class for the Sensors registry component. It handles
+ * PDU packing and unpacking. Methods are either executed on the main thread
+ * or the I/O thread.
+ *
+ * This is an internal class, use |GonkSensorsRegistryInterface| instead.
+ */
+class GonkSensorsRegistryModule
+{
+public:
+ enum {
+ SERVICE_ID = 0x00
+ };
+
+ enum {
+ OPCODE_ERROR = 0x00,
+ OPCODE_REGISTER_MODULE = 0x01,
+ OPCODE_UNREGISTER_MODULE = 0x02
+ };
+
+ virtual nsresult Send(DaemonSocketPDU* aPDU,
+ DaemonSocketResultHandler* aRes) = 0;
+
+ //
+ // Commands
+ //
+
+ nsresult RegisterModuleCmd(uint8_t aId,
+ GonkSensorsRegistryResultHandler* aRes);
+
+ nsresult UnregisterModuleCmd(uint8_t aId,
+ GonkSensorsRegistryResultHandler* aRes);
+
+protected:
+ virtual ~GonkSensorsRegistryModule();
+
+ void HandleSvc(const DaemonSocketPDUHeader& aHeader,
+ DaemonSocketPDU& aPDU, DaemonSocketResultHandler* aRes);
+
+ //
+ // Responses
+ //
+
+ typedef mozilla::ipc::DaemonResultRunnable0<
+ GonkSensorsRegistryResultHandler, void>
+ ResultRunnable;
+
+ typedef mozilla::ipc::DaemonResultRunnable1<
+ GonkSensorsRegistryResultHandler, void, uint32_t, uint32_t>
+ Uint32ResultRunnable;
+
+ typedef mozilla::ipc::DaemonResultRunnable1<
+ GonkSensorsRegistryResultHandler, void, SensorsError, SensorsError>
+ ErrorRunnable;
+
+ void ErrorRsp(const DaemonSocketPDUHeader& aHeader,
+ DaemonSocketPDU& aPDU,
+ GonkSensorsRegistryResultHandler* aRes);
+
+ void RegisterModuleRsp(const DaemonSocketPDUHeader& aHeader,
+ DaemonSocketPDU& aPDU,
+ GonkSensorsRegistryResultHandler* aRes);
+
+ void UnregisterModuleRsp(const DaemonSocketPDUHeader& aHeader,
+ DaemonSocketPDU& aPDU,
+ GonkSensorsRegistryResultHandler* aRes);
+};
+
+/**
+ * This class implements the public interface to the Sensors Registry
+ * component. Use |SensorsInterface::GetRegistryInterface| to retrieve
+ * an instance. All methods run on the main thread.
+ */
+class GonkSensorsRegistryInterface final
+{
+public:
+ friend class GonkSensorsInterface;
+
+ /**
+ * Sends a RegisterModule command to the Sensors daemon. When the
+ * result handler's |RegisterModule| method gets called, the service
+ * has been registered successfully and can be used.
+ *
+ * @param aId The id of the service that is to be registered.
+ * @param aRes The result handler.
+ */
+ void RegisterModule(uint8_t aId, GonkSensorsRegistryResultHandler* aRes);
+
+ /**
+ * Sends an UnregisterModule command to the Sensors daemon. The service
+ * should not be used afterwards until it has been registered again.
+ *
+ * @param aId The id of the service that is to be unregistered.
+ * @param aRes The result handler.
+ */
+ void UnregisterModule(uint8_t aId, GonkSensorsRegistryResultHandler* aRes);
+
+ ~GonkSensorsRegistryInterface();
+
+private:
+ GonkSensorsRegistryInterface(GonkSensorsRegistryModule* aModule);
+
+ void DispatchError(GonkSensorsRegistryResultHandler* aRes,
+ SensorsError aError);
+ void DispatchError(GonkSensorsRegistryResultHandler* aRes,
+ nsresult aRv);
+
+ GonkSensorsRegistryModule* mModule;
+};
+
+} // namespace hal
+} // namespace mozilla
+
+#endif // hal_gonk_GonkSensorsRegistryInterface_h
diff --git a/hal/gonk/GonkSwitch.cpp b/hal/gonk/GonkSwitch.cpp
index b8863e5a1d..1e8ee81f71 100644
--- a/hal/gonk/GonkSwitch.cpp
+++ b/hal/gonk/GonkSwitch.cpp
@@ -61,10 +61,6 @@ public:
GetInitialState();
}
- virtual ~SwitchHandler()
- {
- }
-
bool CheckEvent(NetlinkEvent* aEvent)
{
if (strcmp(GetSubsystem(), aEvent->getSubsystem()) ||
@@ -86,6 +82,10 @@ public:
return mDevice;
}
protected:
+ virtual ~SwitchHandler()
+ {
+ }
+
virtual const char* GetSubsystem()
{
return "switch";
diff --git a/hal/gonk/UeventPoller.cpp b/hal/gonk/UeventPoller.cpp
index a33faf1ca3..d6d66191e6 100644
--- a/hal/gonk/UeventPoller.cpp
+++ b/hal/gonk/UeventPoller.cpp
@@ -31,13 +31,16 @@
#include "HalLog.h"
#include "nsDebug.h"
#include "base/message_loop.h"
+#include "mozilla/ClearOnShutdown.h"
#include "mozilla/FileUtils.h"
-#include "nsAutoPtr.h"
+#include "mozilla/Monitor.h"
#include "nsThreadUtils.h"
#include "nsXULAppAPI.h"
#include "UeventPoller.h"
+using namespace mozilla;
+
namespace mozilla {
namespace hal_impl {
@@ -72,8 +75,9 @@ public:
void UnregisterObserver(IUeventObserver *aObserver)
{
mUeventObserverList.RemoveObserver(aObserver);
- if (mUeventObserverList.Length() == 0)
+ if (mUeventObserverList.Length() == 0) {
ShutdownUevent(); // this will destroy self
+ }
}
private:
@@ -92,13 +96,16 @@ bool
NetlinkPoller::OpenSocket()
{
mSocket.rwget() = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
- if (mSocket.get() < 0)
+ if (mSocket.get() < 0) {
return false;
+ }
int sz = kBuffsize;
- if (setsockopt(mSocket.get(), SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0)
+ if (setsockopt(mSocket.get(), SOL_SOCKET, SO_RCVBUFFORCE, &sz,
+ sizeof(sz)) < 0) {
return false;
+ }
// add FD_CLOEXEC flag
int flags = fcntl(mSocket.get(), F_GETFD);
@@ -106,12 +113,14 @@ NetlinkPoller::OpenSocket()
return false;
}
flags |= FD_CLOEXEC;
- if (fcntl(mSocket.get(), F_SETFD, flags) == -1)
+ if (fcntl(mSocket.get(), F_SETFD, flags) == -1) {
return false;
+ }
// set non-blocking
- if (fcntl(mSocket.get(), F_SETFL, O_NONBLOCK) == -1)
+ if (fcntl(mSocket.get(), F_SETFL, O_NONBLOCK) == -1) {
return false;
+ }
struct sockaddr_nl saddr;
bzero(&saddr, sizeof(saddr));
@@ -150,7 +159,7 @@ NetlinkPoller::OpenSocket()
return true;
}
-static nsAutoPtr sPoller;
+static StaticAutoPtr sPoller;
class UeventInitTask : public Task
{
@@ -190,6 +199,69 @@ NetlinkPoller::OnFileCanReadWithoutBlocking(int fd)
}
}
+static bool sShutdown = false;
+
+class ShutdownNetlinkPoller;
+static StaticAutoPtr sShutdownPoller;
+static Monitor* sMonitor = nullptr;
+
+class ShutdownNetlinkPoller {
+public:
+ ~ShutdownNetlinkPoller()
+ {
+ // This is called from KillClearOnShutdown() on the main thread.
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(XRE_GetIOMessageLoop());
+
+ {
+ MonitorAutoLock lock(*sMonitor);
+
+ XRE_GetIOMessageLoop()->PostTask(
+ FROM_HERE,
+ NewRunnableFunction(ShutdownUeventIOThread));
+
+ while (!sShutdown) {
+ lock.Wait();
+ }
+ }
+
+ sShutdown = true;
+ delete sMonitor;
+ }
+
+ static void MaybeInit()
+ {
+ MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
+ if (sShutdown || sMonitor) {
+ // Don't init twice or init after shutdown.
+ return;
+ }
+
+ sMonitor = new Monitor("ShutdownNetlinkPoller.monitor");
+ {
+ ShutdownNetlinkPoller* shutdownPoller = new ShutdownNetlinkPoller();
+
+ nsCOMPtr runnable = NS_NewRunnableFunction([=] () -> void
+ {
+ sShutdownPoller = shutdownPoller;
+ ClearOnShutdown(&sShutdownPoller); // Must run on the main thread.
+ });
+ MOZ_ASSERT(runnable);
+ MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
+ NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL)));
+ }
+ }
+private:
+ ShutdownNetlinkPoller() = default;
+ static void ShutdownUeventIOThread()
+ {
+ MonitorAutoLock l(*sMonitor);
+ ShutdownUevent(); // Must run on the IO thread.
+ sShutdown = true;
+ l.NotifyAll();
+ }
+};
+
static void
InitializeUevent()
{
@@ -197,6 +269,7 @@ InitializeUevent()
sPoller = new NetlinkPoller();
sPoller->GetIOLoop()->PostTask(FROM_HERE, new UeventInitTask());
+ ShutdownNetlinkPoller::MaybeInit();
}
static void
@@ -210,8 +283,13 @@ RegisterUeventListener(IUeventObserver *aObserver)
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
- if (!sPoller)
+ if (sShutdown) {
+ return;
+ }
+
+ if (!sPoller) {
InitializeUevent();
+ }
sPoller->RegisterObserver(aObserver);
}
@@ -220,6 +298,10 @@ UnregisterUeventListener(IUeventObserver *aObserver)
{
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
+ if (sShutdown) {
+ return;
+ }
+
sPoller->UnregisterObserver(aObserver);
}
diff --git a/hal/linux/UPowerClient.cpp b/hal/linux/UPowerClient.cpp
index 3b769099d9..410aaf3de5 100644
--- a/hal/linux/UPowerClient.cpp
+++ b/hal/linux/UPowerClient.cpp
@@ -7,6 +7,7 @@
#include "HalLog.h"
#include
#include
+#include
#include
#include "nsAutoRef.h"
#include
@@ -417,6 +418,7 @@ UPowerClient::UpdateSavedInfo(GHashTable* aHashTable)
break;
case eState_FullyCharged:
isFull = true;
+ MOZ_FALLTHROUGH;
case eState_Charging:
case eState_PendingCharge:
mCharging = true;
diff --git a/hal/moz.build b/hal/moz.build
index b089f8e490..e3d46a695d 100644
--- a/hal/moz.build
+++ b/hal/moz.build
@@ -49,6 +49,9 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
'gonk/GonkFMRadio.cpp',
'gonk/GonkSensor.cpp',
'gonk/GonkSensorsHelpers.cpp',
+ 'gonk/GonkSensorsInterface.cpp',
+ 'gonk/GonkSensorsPollInterface.cpp',
+ 'gonk/GonkSensorsRegistryInterface.cpp',
'gonk/GonkSwitch.cpp',
'gonk/SystemService.cpp',
'gonk/UeventPoller.cpp',
diff --git a/intl/unicharutil/tools/genUnicodePropertyData.pl b/intl/unicharutil/tools/genUnicodePropertyData.pl
index 41ee4358e6..126563cc08 100644
--- a/intl/unicharutil/tools/genUnicodePropertyData.pl
+++ b/intl/unicharutil/tools/genUnicodePropertyData.pl
@@ -40,8 +40,9 @@
#
# (2) Run this tool using a command line of the form
#
-# perl genUnicodePropertyData.pl \
-# /path/to/harfbuzz/src \
+# perl genUnicodePropertyData.pl \
+# /path/to/harfbuzz/src \
+# /path/to/icu/common/unicode \
# /path/to/UCD-directory
#
# This will generate (or overwrite!) the files
@@ -54,15 +55,17 @@
use strict;
use List::Util qw(first);
-if ($#ARGV != 1) {
+if ($#ARGV != 2) {
print <<__EOT;
# Run this tool using a command line of the form
#
-# perl genUnicodePropertyData.pl \\
-# /path/to/harfbuzz/src \\
+# perl genUnicodePropertyData.pl \\
+# /path/to/harfbuzz/src \\
+# /path/to/icu/common/unicode \\
# /path/to/UCD-directory
#
# where harfbuzz/src is the directory containing harfbuzz .cc and .hh files,
+# icu/common/unicode is the directory containing ICU 'common' public headers,
# and UCD-directory is a directory containing the current Unicode Character
# Database files (UnicodeData.txt, etc), available from
# http://www.unicode.org/Public/UNIDATA/, with additional resources as
@@ -78,190 +81,20 @@ __EOT
exit 0;
}
-# load HB_Script and HB_Category constants
+my $HARFBUZZ = $ARGV[0];
+my $ICU = $ARGV[1];
+my $UNICODE = $ARGV[2];
-# NOTE that HB_SCRIPT_* constants are now "tag" values, NOT sequentially-allocated
-# script codes as used by Glib/Pango/etc.
-# We therefore define a set of MOZ_SCRIPT_* constants that are script _codes_
-# compatible with those libraries, and map these to HB_SCRIPT_* _tags_ as needed.
+# load HB_Category constants
-# CHECK that this matches Pango source (as found for example at
-# http://git.gnome.org/browse/pango/tree/pango/pango-script.h)
-# for as many codes as that defines (currently up through Unicode 5.1)
-# and the GLib enumeration
-# http://developer.gnome.org/glib/2.30/glib-Unicode-Manipulation.html#GUnicodeScript
-# (currently defined up through Unicode 6.0).
-# Constants beyond these may be regarded as unstable for now, but we don't actually
-# depend on the specific values.
-my %scriptCode = (
- INVALID => -1,
- COMMON => 0,
- INHERITED => 1,
- ARABIC => 2,
- ARMENIAN => 3,
- BENGALI => 4,
- BOPOMOFO => 5,
- CHEROKEE => 6,
- COPTIC => 7,
- CYRILLIC => 8,
- DESERET => 9,
- DEVANAGARI => 10,
- ETHIOPIC => 11,
- GEORGIAN => 12,
- GOTHIC => 13,
- GREEK => 14,
- GUJARATI => 15,
- GURMUKHI => 16,
- HAN => 17,
- HANGUL => 18,
- HEBREW => 19,
- HIRAGANA => 20,
- KANNADA => 21,
- KATAKANA => 22,
- KHMER => 23,
- LAO => 24,
- LATIN => 25,
- MALAYALAM => 26,
- MONGOLIAN => 27,
- MYANMAR => 28,
- OGHAM => 29,
- OLD_ITALIC => 30,
- ORIYA => 31,
- RUNIC => 32,
- SINHALA => 33,
- SYRIAC => 34,
- TAMIL => 35,
- TELUGU => 36,
- THAANA => 37,
- THAI => 38,
- TIBETAN => 39,
- CANADIAN_ABORIGINAL => 40,
- YI => 41,
- TAGALOG => 42,
- HANUNOO => 43,
- BUHID => 44,
- TAGBANWA => 45,
-# unicode 4.0 additions
- BRAILLE => 46,
- CYPRIOT => 47,
- LIMBU => 48,
- OSMANYA => 49,
- SHAVIAN => 50,
- LINEAR_B => 51,
- TAI_LE => 52,
- UGARITIC => 53,
-# unicode 4.1 additions
- NEW_TAI_LUE => 54,
- BUGINESE => 55,
- GLAGOLITIC => 56,
- TIFINAGH => 57,
- SYLOTI_NAGRI => 58,
- OLD_PERSIAN => 59,
- KHAROSHTHI => 60,
-# unicode 5.0 additions
- UNKNOWN => 61,
- BALINESE => 62,
- CUNEIFORM => 63,
- PHOENICIAN => 64,
- PHAGS_PA => 65,
- NKO => 66,
-# unicode 5.1 additions
- KAYAH_LI => 67,
- LEPCHA => 68,
- REJANG => 69,
- SUNDANESE => 70,
- SAURASHTRA => 71,
- CHAM => 72,
- OL_CHIKI => 73,
- VAI => 74,
- CARIAN => 75,
- LYCIAN => 76,
- LYDIAN => 77,
-# unicode 5.2 additions
- AVESTAN => 78,
- BAMUM => 79,
- EGYPTIAN_HIEROGLYPHS => 80,
- IMPERIAL_ARAMAIC => 81,
- INSCRIPTIONAL_PAHLAVI => 82,
- INSCRIPTIONAL_PARTHIAN => 83,
- JAVANESE => 84,
- KAITHI => 85,
- LISU => 86,
- MEETEI_MAYEK => 87,
- OLD_SOUTH_ARABIAN => 88,
- OLD_TURKIC => 89,
- SAMARITAN => 90,
- TAI_THAM => 91,
- TAI_VIET => 92,
-# unicode 6.0 additions
- BATAK => 93,
- BRAHMI => 94,
- MANDAIC => 95,
-# unicode 6.1 additions
- CHAKMA => 96,
- MEROITIC_CURSIVE => 97,
- MEROITIC_HIEROGLYPHS => 98,
- MIAO => 99,
- SHARADA => 100,
- SORA_SOMPENG => 101,
- TAKRI => 102,
-# unicode 7.0 additions
- BASSA_VAH => 103,
- CAUCASIAN_ALBANIAN => 104,
- DUPLOYAN => 105,
- ELBASAN => 106,
- GRANTHA => 107,
- KHOJKI => 108,
- KHUDAWADI => 109,
- LINEAR_A => 110,
- MAHAJANI => 111,
- MANICHAEAN => 112,
- MENDE_KIKAKUI => 113,
- MODI => 114,
- MRO => 115,
- NABATAEAN => 116,
- OLD_NORTH_ARABIAN => 117,
- OLD_PERMIC => 118,
- PAHAWH_HMONG => 119,
- PALMYRENE => 120,
- PAU_CIN_HAU => 121,
- PSALTER_PAHLAVI => 122,
- SIDDHAM => 123,
- TIRHUTA => 124,
- WARANG_CITI => 125,
-# unicode 8.0 additions
- AHOM => 126,
- ANATOLIAN_HIEROGLYPHS => 127,
- HATRAN => 128,
- MULTANI => 129,
- OLD_HUNGARIAN => 130,
- SIGNWRITING => 131,
-
-# additional "script" code, not from Unicode (but matches ISO 15924's Zmth tag)
- MATHEMATICAL_NOTATION => 132,
-);
-
-my $sc = -1;
my $cc = -1;
my %catCode;
-my @scriptCodeToTag;
-my @scriptCodeToName;
sub readHarfBuzzHeader
{
my $file = shift;
- open FH, "< $ARGV[0]/$file" or die "can't open harfbuzz header $ARGV[0]/$file\n";
+ open FH, "< $HARFBUZZ/$file" or die "can't open harfbuzz header $HARFBUZZ/$file\n";
while () {
- s/CANADIAN_SYLLABICS/CANADIAN_ABORIGINAL/; # harfbuzz and unicode disagree on this name :(
- if (m/HB_SCRIPT_([A-Z_]+)\s*=\s*HB_TAG\s*\(('.','.','.','.')\)\s*,/) {
- unless (exists $scriptCode{$1}) {
- warn "unknown script name $1 found in $file\n";
- next;
- }
- $sc = $scriptCode{$1};
- $scriptCodeToTag[$sc] = $2;
- $scriptCodeToName[$sc] = $1;
- }
if (m/HB_UNICODE_GENERAL_CATEGORY_([A-Z_]+)/) {
$cc++;
$catCode{$1} = $cc;
@@ -270,16 +103,40 @@ sub readHarfBuzzHeader
close FH;
}
-&readHarfBuzzHeader("hb-common.h");
&readHarfBuzzHeader("hb-unicode.h");
-die "didn't find HarfBuzz script codes\n" if $sc == -1;
die "didn't find HarfBuzz category codes\n" if $cc == -1;
-# Additional code not present in HarfBuzz headers:
-$sc = $scriptCode{"MATHEMATICAL_NOTATION"};
-$scriptCodeToTag[$sc] = "'Z','m','t','h'";
-$scriptCodeToName[$sc] = "MATHEMATICAL_NOTATION";
+my %scriptCode;
+my @scriptCodeToTag;
+my @scriptCodeToName;
+
+my $sc = -1;
+
+sub readIcuHeader
+{
+ my $file = shift;
+ open FH, "< $ICU/$file" or die "can't open ICU header $ICU/$file\n";
+ while () {
+ # adjust for ICU vs UCD naming discrepancies
+ s/LANNA/TAI_THAM/;
+ s/MEITEI_MAYEK/MEETEI_MAYEK/;
+ s/ORKHON/OLD_TURKIC/;
+ s/MENDE/MENDE_KIKAKUI/;
+ s/SIGN_WRITING/SIGNWRITING/;
+ if (m|USCRIPT_([A-Z_]+)\s*=\s*([0-9]+),\s*/\*\s*([A-Z][a-z]{3})\s*\*/|) {
+ $sc = $2;
+ $scriptCode{$1} = $sc;
+ $scriptCodeToTag[$sc] = $3;
+ $scriptCodeToName[$sc] = $1;
+ }
+ }
+ close FH;
+}
+
+&readIcuHeader("uscript.h");
+
+die "didn't find ICU script codes\n" if $sc == -1;
my %xidmodCode = (
'Recommended' => 0,
@@ -317,9 +174,9 @@ my %bidicategoryCode = (
"PDF" => "16", # Pop Directional Format
"NSM" => "17", # Non-Spacing Mark
"BN" => "18", # Boundary Neutral
- "LRI" => "19", # Left-to-Right Isolate
- "RLI" => "20", # Right-to-left Isolate
- "FSI" => "21", # First Strong Isolate
+ "FSI" => "19", # First Strong Isolate
+ "LRI" => "20", # Left-to-Right Isolate
+ "RLI" => "21", # Right-to-left Isolate
"PDI" => "22" # Pop Direcitonal Isolate
);
@@ -404,7 +261,7 @@ my %ucd2hb = (
# read ReadMe.txt
my @versionInfo;
-open FH, "< $ARGV[1]/ReadMe.txt" or die "can't open Unicode ReadMe.txt file\n";
+open FH, "< $UNICODE/ReadMe.txt" or die "can't open Unicode ReadMe.txt file\n";
while () {
chomp;
push @versionInfo, $_;
@@ -418,7 +275,7 @@ my $kLowerToUpper = 0x10000000;
my $kCaseMapCharMask = 0x001fffff;
# read UnicodeData.txt
-open FH, "< $ARGV[1]/UnicodeData.txt" or die "can't open UCD file UnicodeData.txt\n";
+open FH, "< $UNICODE/UnicodeData.txt" or die "can't open UCD file UnicodeData.txt\n";
while () {
chomp;
my @fields = split /;/;
@@ -490,7 +347,7 @@ while () {
close FH;
# read Scripts.txt
-open FH, "< $ARGV[1]/Scripts.txt" or die "can't open UCD file Scripts.txt\n";
+open FH, "< $UNICODE/Scripts.txt" or die "can't open UCD file Scripts.txt\n";
push @versionInfo, "";
while () {
chomp;
@@ -500,8 +357,8 @@ while () {
while () {
if (m/([0-9A-F]{4,6})(?:\.\.([0-9A-F]{4,6}))*\s+;\s+([^ ]+)/) {
my $script = uc($3);
- warn "unknown script $script" unless exists $scriptCode{$script};
- $script = $scriptCode{$script};
+ warn "unknown ICU script $script" unless exists $scriptCode{$script};
+ my $script = $scriptCode{$script};
my $start = hex "0x$1";
my $end = (defined $2) ? hex "0x$2" : $start;
for (my $i = $start; $i <= $end; ++$i) {
@@ -515,7 +372,7 @@ close FH;
my @offsets = ();
push @offsets, 0;
-open FH, "< $ARGV[1]/BidiMirroring.txt" or die "can't open UCD file BidiMirroring.txt\n";
+open FH, "< $UNICODE/BidiMirroring.txt" or die "can't open UCD file BidiMirroring.txt\n";
push @versionInfo, "";
while () {
chomp;
@@ -543,7 +400,7 @@ my %pairedBracketTypeCode = (
'O' => 1,
'C' => 2
);
-open FH, "< $ARGV[1]/BidiBrackets.txt" or die "can't open UCD file BidiBrackets.txt\n";
+open FH, "< $UNICODE/BidiBrackets.txt" or die "can't open UCD file BidiBrackets.txt\n";
push @versionInfo, "";
while () {
chomp;
@@ -570,7 +427,7 @@ my %hangulType = (
'LV' => 0x03,
'LVT' => 0x07
);
-open FH, "< $ARGV[1]/HangulSyllableType.txt" or die "can't open UCD file HangulSyllableType.txt\n";
+open FH, "< $UNICODE/HangulSyllableType.txt" or die "can't open UCD file HangulSyllableType.txt\n";
push @versionInfo, "";
while () {
chomp;
@@ -593,7 +450,7 @@ while () {
close FH;
# read xidmodifications.txt
-open FH, "< $ARGV[1]/security/xidmodifications.txt" or die "can't open UCD file xidmodifications.txt\n";
+open FH, "< $UNICODE/security/xidmodifications.txt" or die "can't open UCD file xidmodifications.txt\n";
push @versionInfo, "";
while () {
chomp;
@@ -616,7 +473,7 @@ while () {
}
close FH;
-open FH, "< $ARGV[1]/Unihan_Variants.txt" or die "can't open UCD file Unihan_Variants.txt (from Unihan.zip)\n";
+open FH, "< $UNICODE/Unihan_Variants.txt" or die "can't open UCD file Unihan_Variants.txt (from Unihan.zip)\n";
push @versionInfo, "";
while () {
chomp;
@@ -653,7 +510,7 @@ while () {
close FH;
# read VerticalOrientation-13.txt
-open FH, "< $ARGV[1]/vertical/VerticalOrientation-13.txt" or die "can't open UTR50 data file VerticalOrientation-13.txt\n";
+open FH, "< $UNICODE/vertical/VerticalOrientation-13.txt" or die "can't open UTR50 data file VerticalOrientation-13.txt\n";
push @versionInfo, "";
while () {
chomp;
@@ -732,21 +589,25 @@ $versionInfo
__END
+print DATA_TABLES "#if !ENABLE_INTL_API\n";
print DATA_TABLES "static const uint32_t sScriptCodeToTag[] = {\n";
for (my $i = 0; $i < scalar @scriptCodeToTag; ++$i) {
- printf DATA_TABLES " HB_TAG(%s)", $scriptCodeToTag[$i];
+ printf DATA_TABLES " HB_TAG('%c','%c','%c','%c')", unpack('cccc', $scriptCodeToTag[$i]);
print DATA_TABLES $i < $#scriptCodeToTag ? ",\n" : "\n";
}
-print DATA_TABLES "};\n\n";
+print DATA_TABLES "};\n";
+print DATA_TABLES "#endif\n\n";
our $totalData = 0;
+print DATA_TABLES "#if !ENABLE_INTL_API\n";
print DATA_TABLES "static const int16_t sMirrorOffsets[] = {\n";
for (my $i = 0; $i < scalar @offsets; ++$i) {
printf DATA_TABLES " $offsets[$i]";
print DATA_TABLES $i < $#offsets ? ",\n" : "\n";
}
-print DATA_TABLES "};\n\n";
+print DATA_TABLES "};\n";
+print DATA_TABLES "#endif\n\n";
print HEADER "#pragma pack(1)\n\n";
@@ -762,11 +623,26 @@ struct nsCharProps1 {
unsigned char mCombiningClass:8;
};
/;
-print DATA_TABLES "#ifndef ENABLE_INTL_API\n";
-&genTables("CharProp1", $type, "nsCharProps1", 11, 5, \&sprintCharProps1, 1, 2, 1);
-print DATA_TABLES "#endif\n\n";
+&genTables("#if !ENABLE_INTL_API", "#endif",
+ "CharProp1", $type, "nsCharProps1", 11, 5, \&sprintCharProps1, 1, 2, 1);
-sub sprintCharProps2
+sub sprintCharProps2_short
+{
+ my $usv = shift;
+ return sprintf("{%d,%d,%d},",
+ $pairedBracketType[$usv], $verticalOrientation[$usv], $xidmod[$usv]);
+}
+$type = q/
+struct nsCharProps2 {
+ unsigned char mPairedBracketType:2;
+ unsigned char mVertOrient:2;
+ unsigned char mXidmod:4;
+};
+/;
+&genTables("#if ENABLE_INTL_API", "#endif",
+ "CharProp2", $type, "nsCharProps2", 9, 7, \&sprintCharProps2_short, 16, 1, 1);
+
+sub sprintCharProps2_full
{
my $usv = shift;
return sprintf("{%d,%d,%d,%d,%d,%d,%d},",
@@ -785,7 +661,8 @@ struct nsCharProps2 {
unsigned char mVertOrient:2;
};
|;
-&genTables("CharProp2", $type, "nsCharProps2", 11, 5, \&sprintCharProps2, 16, 4, 1);
+&genTables("#if !ENABLE_INTL_API", "#endif",
+ "CharProp2", $type, "nsCharProps2", 11, 5, \&sprintCharProps2_full, 16, 4, 1);
print HEADER "#pragma pack()\n\n";
@@ -800,21 +677,22 @@ sub sprintHanVariants
}
return sprintf("0x%02x,", $val);
}
-&genTables("HanVariant", "", "uint8_t", 9, 7, \&sprintHanVariants, 2, 1, 4);
+## Han Variant data currently unused but may be needed in future, see bug 857481
+## &genTables("", "", "HanVariant", "", "uint8_t", 9, 7, \&sprintHanVariants, 2, 1, 4);
sub sprintFullWidth
{
my $usv = shift;
return sprintf("0x%04x,", $fullWidth[$usv]);
}
-&genTables("FullWidth", "", "uint16_t", 10, 6, \&sprintFullWidth, 0, 2, 1);
+&genTables("", "", "FullWidth", "", "uint16_t", 10, 6, \&sprintFullWidth, 0, 2, 1);
sub sprintCasemap
{
my $usv = shift;
return sprintf("0x%08x,", $casemap[$usv]);
}
-&genTables("CaseMap", "", "uint32_t", 11, 5, \&sprintCasemap, 1, 4, 1);
+&genTables("", "", "CaseMap", "", "uint32_t", 11, 5, \&sprintCasemap, 1, 4, 1);
print STDERR "Total data = $totalData\n";
@@ -826,8 +704,16 @@ printf DATA_TABLES "const uint32_t kCaseMapCharMask = 0x%08x;\n\n", $kCaseMapCha
sub genTables
{
- my ($prefix, $typedef, $type, $indexBits, $charBits, $func, $maxPlane, $bytesPerEntry, $charsPerEntry) = @_;
+ my ($guardBegin, $guardEnd,
+ $prefix, $typedef, $type, $indexBits, $charBits, $func, $maxPlane, $bytesPerEntry, $charsPerEntry) = @_;
+ if ($typedef ne '') {
+ print HEADER "$guardBegin\n";
+ print HEADER "$typedef\n";
+ print HEADER "$guardEnd\n\n";
+ }
+
+ print DATA_TABLES "\n$guardBegin\n";
print DATA_TABLES "#define k${prefix}MaxPlane $maxPlane\n";
print DATA_TABLES "#define k${prefix}IndexBits $indexBits\n";
print DATA_TABLES "#define k${prefix}CharBits $charBits\n";
@@ -888,8 +774,6 @@ sub genTables
}
print DATA_TABLES "};\n\n";
- print HEADER "$typedef\n\n" if $typedef ne '';
-
my $pageLen = $charsPerPage / $charsPerEntry;
print DATA_TABLES "static const $type s${prefix}Values[$chCount][$pageLen] = {\n";
for (my $i = 0; $i < scalar @char; ++$i) {
@@ -897,7 +781,8 @@ sub genTables
print DATA_TABLES $char[$i];
print DATA_TABLES $i < $#char ? "},\n" : "}\n";
}
- print DATA_TABLES "};\n\n";
+ print DATA_TABLES "};\n";
+ print DATA_TABLES "$guardEnd\n";
my $dataSize = $pmCount * $indexLen * $pmBits/8 +
$chCount * $pageLen * $bytesPerEntry +
diff --git a/intl/unicharutil/util/nsBidiUtils.h b/intl/unicharutil/util/nsBidiUtils.h
index ce2ac307b8..f002dd508a 100644
--- a/intl/unicharutil/util/nsBidiUtils.h
+++ b/intl/unicharutil/util/nsBidiUtils.h
@@ -14,7 +14,8 @@
* for the detailed definition of the following categories
*
* The values here must match the equivalents in %bidicategorycode in
- * mozilla/intl/unicharutil/tools/genUnicodePropertyData.pl
+ * mozilla/intl/unicharutil/tools/genUnicodePropertyData.pl,
+ * and must also match the values used by ICU's UCharDirection.
*/
enum nsCharType {
@@ -37,9 +38,9 @@ enum nsCharType {
eCharType_PopDirectionalFormat = 16,
eCharType_DirNonSpacingMark = 17,
eCharType_BoundaryNeutral = 18,
- eCharType_LeftToRightIsolate = 19,
- eCharType_RightToLeftIsolate = 20,
- eCharType_FirstStrongIsolate = 21,
+ eCharType_FirstStrongIsolate = 19,
+ eCharType_LeftToRightIsolate = 20,
+ eCharType_RightToLeftIsolate = 21,
eCharType_PopDirectionalIsolate = 22,
eCharType_CharTypeCount
};
diff --git a/intl/unicharutil/util/nsUnicodeProperties.cpp b/intl/unicharutil/util/nsUnicodeProperties.cpp
index 22810e5f84..6beab3a967 100644
--- a/intl/unicharutil/util/nsUnicodeProperties.cpp
+++ b/intl/unicharutil/util/nsUnicodeProperties.cpp
@@ -11,12 +11,12 @@
#if ENABLE_INTL_API
#include "unicode/uchar.h"
+#include "unicode/uscript.h"
#endif
#define UNICODE_BMP_LIMIT 0x10000
#define UNICODE_LIMIT 0x110000
-
#ifndef ENABLE_INTL_API
static const nsCharProps1&
GetCharProps1(uint32_t aCh)
@@ -56,14 +56,21 @@ GetCharProps2(uint32_t aCh)
NS_NOTREACHED("Getting CharProps for codepoint outside Unicode range");
// Default values for unassigned
+ using namespace mozilla::unicode;
static const nsCharProps2 undefined = {
- MOZ_SCRIPT_UNKNOWN, // Script code
- 0, // East Asian Width
- HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED, // General Category
- eCharType_LeftToRight, // Bidi Category
- mozilla::unicode::XIDMOD_NOT_CHARS, // Xidmod
- -1, // Numeric Value
- mozilla::unicode::HVT_NotHan // Han variant
+#if ENABLE_INTL_API
+ PAIRED_BRACKET_TYPE_NONE,
+ VERTICAL_ORIENTATION_R,
+ XIDMOD_NOT_CHARS
+#else
+ MOZ_SCRIPT_UNKNOWN,
+ PAIRED_BRACKET_TYPE_NONE,
+ HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED,
+ eCharType_LeftToRight,
+ XIDMOD_NOT_CHARS,
+ -1, // Numeric Value
+ VERTICAL_ORIENTATION_R
+#endif
};
return undefined;
}
@@ -93,7 +100,7 @@ to provide the most compact storage, depending on the distribution
of values.
*/
-nsIUGenCategory::nsUGenCategory sDetailedToGeneralCategory[] = {
+const nsIUGenCategory::nsUGenCategory sDetailedToGeneralCategory[] = {
/*
* The order here corresponds to the HB_UNICODE_GENERAL_CATEGORY_* constants
* of the hb_unicode_general_category_t enum in gfx/harfbuzz/src/hb-unicode.h.
@@ -130,6 +137,69 @@ nsIUGenCategory::nsUGenCategory sDetailedToGeneralCategory[] = {
/* SPACE_SEPARATOR */ nsIUGenCategory::kSeparator
};
+#ifdef ENABLE_INTL_API
+const hb_unicode_general_category_t sICUtoHBcategory[U_CHAR_CATEGORY_COUNT] = {
+ HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED, // U_GENERAL_OTHER_TYPES = 0,
+ HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER, // U_UPPERCASE_LETTER = 1,
+ HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER, // U_LOWERCASE_LETTER = 2,
+ HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER, // U_TITLECASE_LETTER = 3,
+ HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER, // U_MODIFIER_LETTER = 4,
+ HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER, // U_OTHER_LETTER = 5,
+ HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK, // U_NON_SPACING_MARK = 6,
+ HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK, // U_ENCLOSING_MARK = 7,
+ HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK, // U_COMBINING_SPACING_MARK = 8,
+ HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER, // U_DECIMAL_DIGIT_NUMBER = 9,
+ HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER, // U_LETTER_NUMBER = 10,
+ HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER, // U_OTHER_NUMBER = 11,
+ HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR, // U_SPACE_SEPARATOR = 12,
+ HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR, // U_LINE_SEPARATOR = 13,
+ HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR, // U_PARAGRAPH_SEPARATOR = 14,
+ HB_UNICODE_GENERAL_CATEGORY_CONTROL, // U_CONTROL_CHAR = 15,
+ HB_UNICODE_GENERAL_CATEGORY_FORMAT, // U_FORMAT_CHAR = 16,
+ HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE, // U_PRIVATE_USE_CHAR = 17,
+ HB_UNICODE_GENERAL_CATEGORY_SURROGATE, // U_SURROGATE = 18,
+ HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION, // U_DASH_PUNCTUATION = 19,
+ HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION, // U_START_PUNCTUATION = 20,
+ HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION, // U_END_PUNCTUATION = 21,
+ HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION, // U_CONNECTOR_PUNCTUATION = 22,
+ HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION, // U_OTHER_PUNCTUATION = 23,
+ HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL, // U_MATH_SYMBOL = 24,
+ HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL, // U_CURRENCY_SYMBOL = 25,
+ HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL, // U_MODIFIER_SYMBOL = 26,
+ HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL, // U_OTHER_SYMBOL = 27,
+ HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION, // U_INITIAL_PUNCTUATION = 28,
+ HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION, // U_FINAL_PUNCTUATION = 29,
+};
+#endif
+
+uint8_t GetGeneralCategory(uint32_t aCh) {
+#if ENABLE_INTL_API
+ return sICUtoHBcategory[u_charType(aCh)];
+#else
+ return GetCharProps2(aCh).mCategory;
+#endif
+}
+
+nsCharType GetBidiCat(uint32_t aCh) {
+#if ENABLE_INTL_API
+ return nsCharType(u_charDirection(aCh));
+#else
+ return nsCharType(GetCharProps2(aCh).mBidiCategory);
+#endif
+}
+
+int8_t GetNumericValue(uint32_t aCh) {
+#if ENABLE_INTL_API
+ UNumericType type =
+ UNumericType(u_getIntPropertyValue(aCh, UCHAR_NUMERIC_TYPE));
+ return type == U_NT_DECIMAL || type == U_NT_DIGIT
+ ? int8_t(u_getNumericValue(aCh))
+ : -1;
+#else
+ return GetCharProps2(aCh).mNumericValue;
+#endif
+}
+
uint32_t
GetMirroredChar(uint32_t aCh)
{
@@ -160,14 +230,30 @@ GetCombiningClass(uint32_t aCh)
#endif
}
+uint8_t
+GetScriptCode(uint32_t aCh)
+{
+#if ENABLE_INTL_API
+ UErrorCode err = U_ZERO_ERROR;
+ return uscript_getScript(aCh, &err);
+#else
+ return GetCharProps2(aCh).mScriptCode;
+#endif
+}
+
uint32_t
GetScriptTagForCode(int32_t aScriptCode)
{
+#if ENABLE_INTL_API
+ const char* tag = uscript_getShortName(UScriptCode(aScriptCode));
+ return HB_TAG(tag[0], tag[1], tag[2], tag[3]);
+#else
// this will safely return 0 for negative script codes, too :)
if (uint32_t(aScriptCode) > ArrayLength(sScriptCodeToTag)) {
return 0;
}
return sScriptCodeToTag[aScriptCode];
+#endif
}
PairedBracketType GetPairedBracketType(uint32_t aCh)
@@ -254,6 +340,7 @@ GetTitlecaseForAll(uint32_t aCh)
return aCh;
}
+#if 0 // currently unused - bug 857481
HanVariantType
GetHanVariant(uint32_t aCh)
{
@@ -272,6 +359,7 @@ GetHanVariant(uint32_t aCh)
// extract the appropriate 2-bit field from the value
return HanVariantType((v >> ((aCh & 3) * 2)) & 3);
}
+#endif
uint32_t
GetFullWidth(uint32_t aCh)
diff --git a/intl/unicharutil/util/nsUnicodeProperties.h b/intl/unicharutil/util/nsUnicodeProperties.h
index 3abf660b0d..8bee5f847b 100644
--- a/intl/unicharutil/util/nsUnicodeProperties.h
+++ b/intl/unicharutil/util/nsUnicodeProperties.h
@@ -16,7 +16,7 @@ namespace mozilla {
namespace unicode {
-extern nsIUGenCategory::nsUGenCategory sDetailedToGeneralCategory[];
+extern const nsIUGenCategory::nsUGenCategory sDetailedToGeneralCategory[];
// Return whether the char has a mirrored-pair counterpart.
uint32_t GetMirroredChar(uint32_t aCh);
@@ -26,25 +26,19 @@ bool HasMirroredChar(uint32_t aChr);
uint8_t GetCombiningClass(uint32_t aCh);
// returns the detailed General Category in terms of HB_UNICODE_* values
-inline uint8_t GetGeneralCategory(uint32_t aCh) {
- return GetCharProps2(aCh).mCategory;
-}
+uint8_t GetGeneralCategory(uint32_t aCh);
// returns the simplified Gen Category as defined in nsIUGenCategory
inline nsIUGenCategory::nsUGenCategory GetGenCategory(uint32_t aCh) {
return sDetailedToGeneralCategory[GetGeneralCategory(aCh)];
}
-inline uint8_t GetScriptCode(uint32_t aCh) {
- return GetCharProps2(aCh).mScriptCode;
-}
+nsCharType GetBidiCat(uint32_t aCh);
+
+uint8_t GetScriptCode(uint32_t aCh);
uint32_t GetScriptTagForCode(int32_t aScriptCode);
-inline nsCharType GetBidiCat(uint32_t aCh) {
- return nsCharType(GetCharProps2(aCh).mBidiCategory);
-}
-
/* This MUST match the values assigned by genUnicodePropertyData.pl! */
enum VerticalOrientation {
VERTICAL_ORIENTATION_U = 0,
@@ -93,10 +87,9 @@ inline XidmodType GetIdentifierModification(uint32_t aCh) {
* To restrict to decimal digits, the caller should also check whether
* GetGeneralCategory returns HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER
*/
-inline int8_t GetNumericValue(uint32_t aCh) {
- return GetCharProps2(aCh).mNumericValue;
-}
+int8_t GetNumericValue(uint32_t aCh);
+#if 0 // currently unused - bug 857481
enum HanVariantType {
HVT_NotHan = 0x0,
HVT_SimplifiedOnly = 0x1,
@@ -105,6 +98,7 @@ enum HanVariantType {
};
HanVariantType GetHanVariant(uint32_t aCh);
+#endif
uint32_t GetFullWidth(uint32_t aCh);
diff --git a/js/xpconnect/tests/chrome/test_bug853283.xul b/js/xpconnect/tests/chrome/test_bug853283.xul
index 8275809bd5..ac59ad9a77 100644
--- a/js/xpconnect/tests/chrome/test_bug853283.xul
+++ b/js/xpconnect/tests/chrome/test_bug853283.xul
@@ -30,7 +30,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=853283
var sb = new Cu.Sandbox(window);
sb.iwin = iwin;
sb.ok = ok;
- Cu.evalInSandbox('try {iwin.navigator.mozApps; ok(true, "Didnt throw"); } catch (e) { ok(false, "Threw: " + e);}', sb);
+ Cu.evalInSandbox('try {iwin.navigator.mozContacts; ok(true, "Didnt throw"); } catch (e) { ok(false, "Threw: " + e);}', sb);
SimpleTest.finish();
}
diff --git a/layout/generic/MathMLTextRunFactory.cpp b/layout/generic/MathMLTextRunFactory.cpp
index 1fc3cb148a..3f7337f0d9 100644
--- a/layout/generic/MathMLTextRunFactory.cpp
+++ b/layout/generic/MathMLTextRunFactory.cpp
@@ -773,12 +773,15 @@ MathMLTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
}
if (!child)
return;
+
+ typedef gfxTextRun::Range Range;
+
// Copy potential linebreaks into child so they're preserved
// (and also child will be shaped appropriately)
NS_ASSERTION(convertedString.Length() == canBreakBeforeArray.Length(),
"Dropped characters or break-before values somewhere!");
- child->SetPotentialLineBreaks(0, canBreakBeforeArray.Length(),
- canBreakBeforeArray.Elements());
+ Range range(0, uint32_t(canBreakBeforeArray.Length()));
+ child->SetPotentialLineBreaks(range, canBreakBeforeArray.Elements());
if (transformedChild) {
transformedChild->FinishSettingProperties(aRefDrawTarget, aMFR);
}
@@ -796,6 +799,6 @@ MathMLTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
// We can't steal the data because the child may be cached and stealing
// the data would break the cache.
aTextRun->ResetGlyphRuns();
- aTextRun->CopyGlyphDataFrom(child, 0, child->GetLength(), 0);
+ aTextRun->CopyGlyphDataFrom(child, Range(child), 0);
}
}
diff --git a/layout/generic/TextOverflow.cpp b/layout/generic/TextOverflow.cpp
index 62e64a9345..28e89e0aa1 100644
--- a/layout/generic/TextOverflow.cpp
+++ b/layout/generic/TextOverflow.cpp
@@ -252,8 +252,8 @@ nsDisplayTextOverflowMarker::PaintTextToContext(nsRenderingContext* aCtx,
NS_ASSERTION(!textRun->IsRightToLeft(),
"Ellipsis textruns should always be LTR!");
gfxPoint gfxPt(pt.x, pt.y);
- textRun->Draw(aCtx->ThebesContext(), gfxPt, DrawMode::GLYPH_FILL,
- 0, textRun->GetLength(), nullptr, nullptr, nullptr);
+ textRun->Draw(gfxTextRun::Range(textRun), gfxPt,
+ gfxTextRun::DrawParams(aCtx->ThebesContext()));
}
} else {
RefPtr fm;
@@ -803,7 +803,7 @@ TextOverflow::Marker::SetupString(nsIFrame* aFrame)
if (mStyle->mType == NS_STYLE_TEXT_OVERFLOW_ELLIPSIS) {
gfxTextRun* textRun = GetEllipsisTextRun(aFrame);
if (textRun) {
- mISize = textRun->GetAdvanceWidth(0, textRun->GetLength(), nullptr);
+ mISize = textRun->GetAdvanceWidth();
} else {
mISize = 0;
}
diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp
index bf9fb2468e..8ca8493845 100644
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -979,8 +979,9 @@ public:
virtual void SetBreaks(uint32_t aOffset, uint32_t aLength,
uint8_t* aBreakBefore) override {
- if (mTextRun->SetPotentialLineBreaks(aOffset + mOffsetIntoTextRun, aLength,
- aBreakBefore)) {
+ gfxTextRun::Range range(aOffset + mOffsetIntoTextRun,
+ aOffset + mOffsetIntoTextRun + aLength);
+ if (mTextRun->SetPotentialLineBreaks(range, aBreakBefore)) {
// Be conservative and assume that some breaks have been set
mTextRun->ClearFlagBits(nsTextFrameUtils::TEXT_NO_BREAKS);
}
@@ -2927,18 +2928,20 @@ static bool IsChineseOrJapanese(nsTextFrame* aFrame)
#ifdef DEBUG
static bool IsInBounds(const gfxSkipCharsIterator& aStart, int32_t aContentLength,
- uint32_t aOffset, uint32_t aLength) {
- if (aStart.GetSkippedOffset() > aOffset)
+ gfxTextRun::Range aRange) {
+ if (aStart.GetSkippedOffset() > aRange.start)
return false;
if (aContentLength == INT32_MAX)
return true;
gfxSkipCharsIterator iter(aStart);
iter.AdvanceOriginal(aContentLength);
- return iter.GetSkippedOffset() >= aOffset + aLength;
+ return iter.GetSkippedOffset() >= aRange.end;
}
#endif
class MOZ_STACK_CLASS PropertyProvider : public gfxTextRun::PropertyProvider {
+ typedef gfxTextRun::Range Range;
+
public:
/**
* Use this constructor for reflow, when we don't know what text is
@@ -3002,10 +3005,9 @@ public:
void InitializeForMeasure();
- virtual void GetSpacing(uint32_t aStart, uint32_t aLength, Spacing* aSpacing);
+ virtual void GetSpacing(Range aRange, Spacing* aSpacing);
virtual gfxFloat GetHyphenWidth();
- virtual void GetHyphenationBreaks(uint32_t aStart, uint32_t aLength,
- bool* aBreakBefore);
+ virtual void GetHyphenationBreaks(Range aRange, bool* aBreakBefore);
virtual int8_t GetHyphensOption() {
return mTextStyle->mHyphens;
}
@@ -3018,14 +3020,13 @@ public:
return mTextRun->GetAppUnitsPerDevUnit();
}
- void GetSpacingInternal(uint32_t aStart, uint32_t aLength, Spacing* aSpacing,
- bool aIgnoreTabs);
+ void GetSpacingInternal(Range aRange, Spacing* aSpacing, bool aIgnoreTabs);
/**
* Compute the justification information in given DOM range, and fill data
* necessary for computation of spacing.
*/
- void ComputeJustification(int32_t aOffset, int32_t aLength);
+ void ComputeJustification(Range aRange);
const nsStyleText* StyleText() { return mTextStyle; }
nsTextFrame* GetFrame() { return mFrame; }
@@ -3052,7 +3053,7 @@ public:
return mFontMetrics;
}
- void CalcTabWidths(uint32_t aTransformedStart, uint32_t aTransformedLength);
+ void CalcTabWidths(Range aTransformedRange);
const gfxSkipCharsIterator& GetEndHint() { return mTempIterator; }
@@ -3147,16 +3148,16 @@ static void FindClusterEnd(gfxTextRun* aTextRun, int32_t aOriginalEnd,
}
void
-PropertyProvider::ComputeJustification(int32_t aOffset, int32_t aLength)
+PropertyProvider::ComputeJustification(Range aRange)
{
bool isCJ = IsChineseOrJapanese(mFrame);
- nsSkipCharsRunIterator
- run(mStart, nsSkipCharsRunIterator::LENGTH_INCLUDES_SKIPPED, aLength);
- run.SetOriginalOffset(aOffset);
+ nsSkipCharsRunIterator run(
+ mStart, nsSkipCharsRunIterator::LENGTH_INCLUDES_SKIPPED, aRange.Length());
+ run.SetOriginalOffset(aRange.start);
mJustificationArrayStart = run.GetSkippedOffset();
MOZ_ASSERT(mJustificationAssignments.IsEmpty());
- mJustificationAssignments.SetCapacity(aLength);
+ mJustificationAssignments.SetCapacity(aRange.Length());
while (run.NextRun()) {
uint32_t originalOffset = run.GetOriginalOffset();
uint32_t skippedOffset = run.GetSkippedOffset();
@@ -3215,10 +3216,9 @@ PropertyProvider::ComputeJustification(int32_t aOffset, int32_t aLength)
// aStart, aLength in transformed string offsets
void
-PropertyProvider::GetSpacing(uint32_t aStart, uint32_t aLength,
- Spacing* aSpacing)
+PropertyProvider::GetSpacing(Range aRange, Spacing* aSpacing)
{
- GetSpacingInternal(aStart, aLength, aSpacing,
+ GetSpacingInternal(aRange, aSpacing,
(mTextRun->GetFlags() & nsTextFrameUtils::TEXT_HAS_TAB) == 0);
}
@@ -3232,28 +3232,28 @@ CanAddSpacingAfter(gfxTextRun* aTextRun, uint32_t aOffset)
}
void
-PropertyProvider::GetSpacingInternal(uint32_t aStart, uint32_t aLength,
- Spacing* aSpacing, bool aIgnoreTabs)
+PropertyProvider::GetSpacingInternal(Range aRange, Spacing* aSpacing,
+ bool aIgnoreTabs)
{
- NS_PRECONDITION(IsInBounds(mStart, mLength, aStart, aLength), "Range out of bounds");
+ NS_PRECONDITION(IsInBounds(mStart, mLength, aRange), "Range out of bounds");
uint32_t index;
- for (index = 0; index < aLength; ++index) {
+ for (index = 0; index < aRange.Length(); ++index) {
aSpacing[index].mBefore = 0.0;
aSpacing[index].mAfter = 0.0;
}
// Find our offset into the original+transformed string
gfxSkipCharsIterator start(mStart);
- start.SetSkippedOffset(aStart);
+ start.SetSkippedOffset(aRange.start);
// First, compute the word and letter spacing
if (mWordSpacing || mLetterSpacing) {
// Iterate over non-skipped characters
- nsSkipCharsRunIterator
- run(start, nsSkipCharsRunIterator::LENGTH_UNSKIPPED_ONLY, aLength);
+ nsSkipCharsRunIterator run(
+ start, nsSkipCharsRunIterator::LENGTH_UNSKIPPED_ONLY, aRange.Length());
while (run.NextRun()) {
- uint32_t runOffsetInSubstring = run.GetSkippedOffset() - aStart;
+ uint32_t runOffsetInSubstring = run.GetSkippedOffset() - aRange.start;
gfxSkipCharsIterator iter = run.GetPos();
for (int32_t i = 0; i < run.GetRunLength(); ++i) {
if (CanAddSpacingAfter(mTextRun, run.GetSkippedOffset() + i)) {
@@ -3267,7 +3267,8 @@ PropertyProvider::GetSpacingInternal(uint32_t aStart, uint32_t aLength,
iter.SetSkippedOffset(run.GetSkippedOffset() + i);
FindClusterEnd(mTextRun, run.GetOriginalOffset() + run.GetRunLength(),
&iter);
- aSpacing[iter.GetSkippedOffset() - aStart].mAfter += mWordSpacing;
+ uint32_t runOffset = iter.GetSkippedOffset() - aRange.start;
+ aSpacing[runOffset].mAfter += mWordSpacing;
}
}
}
@@ -3279,10 +3280,11 @@ PropertyProvider::GetSpacingInternal(uint32_t aStart, uint32_t aLength,
// Now add tab spacing, if there is any
if (!aIgnoreTabs) {
- CalcTabWidths(aStart, aLength);
+ CalcTabWidths(aRange);
if (mTabWidths) {
mTabWidths->ApplySpacing(aSpacing,
- aStart - mStart.GetSkippedOffset(), aLength);
+ aRange.start - mStart.GetSkippedOffset(),
+ aRange.Length());
}
}
@@ -3293,15 +3295,16 @@ PropertyProvider::GetSpacingInternal(uint32_t aStart, uint32_t aLength,
// ignore those spaces.
auto arrayEnd = mJustificationArrayStart +
static_cast(mJustificationAssignments.Length());
- auto end = std::min(aStart + aLength, arrayEnd);
- MOZ_ASSERT(aStart >= mJustificationArrayStart);
+ auto end = std::min(aRange.end, arrayEnd);
+ MOZ_ASSERT(aRange.start >= mJustificationArrayStart);
JustificationApplicationState state(
mTotalJustificationGaps, NSToCoordRound(mJustificationSpacing));
- for (auto i = aStart; i < end; i++) {
+ for (auto i = aRange.start; i < end; i++) {
const auto& assign =
mJustificationAssignments[i - mJustificationArrayStart];
- aSpacing[i - aStart].mBefore += state.Consume(assign.mGapsAtStart);
- aSpacing[i - aStart].mAfter += state.Consume(assign.mGapsAtEnd);
+ uint32_t offset = i - aRange.start;
+ aSpacing[offset].mBefore += state.Consume(assign.mGapsAtStart);
+ aSpacing[offset].mAfter += state.Consume(assign.mGapsAtEnd);
}
}
}
@@ -3331,7 +3334,7 @@ AdvanceToNextTab(gfxFloat aX, nsIFrame* aFrame,
}
void
-PropertyProvider::CalcTabWidths(uint32_t aStart, uint32_t aLength)
+PropertyProvider::CalcTabWidths(Range aRange)
{
if (!mTabWidths) {
if (mReflowing && !mLineContainer) {
@@ -3346,7 +3349,7 @@ PropertyProvider::CalcTabWidths(uint32_t aStart, uint32_t aLength)
// If we're not reflowing, we should have already computed the
// tab widths; check that they're available as far as the last
// tab character present (if any)
- for (uint32_t i = aStart + aLength; i > aStart; --i) {
+ for (uint32_t i = aRange.end; i > aRange.start; --i) {
if (mTextRun->CharIsTab(i - 1)) {
uint32_t startOffset = mStart.GetSkippedOffset();
NS_ASSERTION(mTabWidths && mTabWidths->mLimit + startOffset >= i,
@@ -3360,18 +3363,18 @@ PropertyProvider::CalcTabWidths(uint32_t aStart, uint32_t aLength)
}
uint32_t startOffset = mStart.GetSkippedOffset();
- MOZ_ASSERT(aStart >= startOffset, "wrong start offset");
- MOZ_ASSERT(aStart + aLength <= startOffset + mLength, "beyond the end");
+ MOZ_ASSERT(aRange.start >= startOffset, "wrong start offset");
+ MOZ_ASSERT(aRange.end <= startOffset + mLength, "beyond the end");
uint32_t tabsEnd =
(mTabWidths ? mTabWidths->mLimit : mTabWidthsAnalyzedLimit) + startOffset;
- if (tabsEnd < aStart + aLength) {
+ if (tabsEnd < aRange.end) {
NS_ASSERTION(mReflowing,
"We need precomputed tab widths, but don't have enough.");
gfxFloat tabWidth = -1;
- for (uint32_t i = tabsEnd; i < aStart + aLength; ++i) {
+ for (uint32_t i = tabsEnd; i < aRange.end; ++i) {
Spacing spacing;
- GetSpacingInternal(i, 1, &spacing, true);
+ GetSpacingInternal(Range(i, i + 1), &spacing, true);
mOffsetFromBlockOriginForTabs += spacing.mBefore;
if (!mTextRun->CharIsTab(i)) {
@@ -3382,7 +3385,7 @@ PropertyProvider::CalcTabWidths(uint32_t aStart, uint32_t aLength)
++clusterEnd;
}
mOffsetFromBlockOriginForTabs +=
- mTextRun->GetAdvanceWidth(i, clusterEnd - i, nullptr);
+ mTextRun->GetAdvanceWidth(Range(i, clusterEnd), nullptr);
}
} else {
if (!mTabWidths) {
@@ -3400,7 +3403,7 @@ PropertyProvider::CalcTabWidths(uint32_t aStart, uint32_t aLength)
}
if (mTabWidths) {
- mTabWidths->mLimit = aStart + aLength - startOffset;
+ mTabWidths->mLimit = aRange.end - startOffset;
}
}
@@ -3408,7 +3411,7 @@ PropertyProvider::CalcTabWidths(uint32_t aStart, uint32_t aLength)
// Delete any stale property that may be left on the frame
mFrame->Properties().Delete(TabWidthProperty());
mTabWidthsAnalyzedLimit = std::max(mTabWidthsAnalyzedLimit,
- aStart + aLength - startOffset);
+ aRange.end - startOffset);
}
}
@@ -3422,23 +3425,22 @@ PropertyProvider::GetHyphenWidth()
}
void
-PropertyProvider::GetHyphenationBreaks(uint32_t aStart, uint32_t aLength,
- bool* aBreakBefore)
+PropertyProvider::GetHyphenationBreaks(Range aRange, bool* aBreakBefore)
{
- NS_PRECONDITION(IsInBounds(mStart, mLength, aStart, aLength), "Range out of bounds");
+ NS_PRECONDITION(IsInBounds(mStart, mLength, aRange), "Range out of bounds");
NS_PRECONDITION(mLength != INT32_MAX, "Can't call this with undefined length");
if (!mTextStyle->WhiteSpaceCanWrap(mFrame) ||
mTextStyle->mHyphens == NS_STYLE_HYPHENS_NONE)
{
- memset(aBreakBefore, false, aLength*sizeof(bool));
+ memset(aBreakBefore, false, aRange.Length() * sizeof(bool));
return;
}
// Iterate through the original-string character runs
- nsSkipCharsRunIterator
- run(mStart, nsSkipCharsRunIterator::LENGTH_UNSKIPPED_ONLY, aLength);
- run.SetSkippedOffset(aStart);
+ nsSkipCharsRunIterator run(
+ mStart, nsSkipCharsRunIterator::LENGTH_UNSKIPPED_ONLY, aRange.Length());
+ run.SetSkippedOffset(aRange.start);
// We need to visit skipped characters so that we can detect SHY
run.SetVisitSkipped();
@@ -3457,7 +3459,7 @@ PropertyProvider::GetHyphenationBreaks(uint32_t aStart, uint32_t aLength,
allowHyphenBreakBeforeNextChar =
mFrag->CharAt(run.GetOriginalOffset() + run.GetRunLength() - 1) == CH_SHY;
} else {
- int32_t runOffsetInSubstring = run.GetSkippedOffset() - aStart;
+ int32_t runOffsetInSubstring = run.GetSkippedOffset() - aRange.start;
memset(aBreakBefore + runOffsetInSubstring, false, run.GetRunLength()*sizeof(bool));
// Don't allow hyphen breaks at the start of the line
aBreakBefore[runOffsetInSubstring] = allowHyphenBreakBeforeNextChar &&
@@ -3468,8 +3470,8 @@ PropertyProvider::GetHyphenationBreaks(uint32_t aStart, uint32_t aLength,
}
if (mTextStyle->mHyphens == NS_STYLE_HYPHENS_AUTO) {
- for (uint32_t i = 0; i < aLength; ++i) {
- if (mTextRun->CanHyphenateBefore(aStart + i)) {
+ for (uint32_t i = 0; i < aRange.Length(); ++i) {
+ if (mTextRun->CanHyphenateBefore(aRange.start + i)) {
aBreakBefore[i] = true;
}
}
@@ -3497,12 +3499,6 @@ PropertyProvider::InitializeForMeasure()
}
-static uint32_t GetSkippedDistance(const gfxSkipCharsIterator& aStart,
- const gfxSkipCharsIterator& aEnd)
-{
- return aEnd.GetSkippedOffset() - aStart.GetSkippedOffset();
-}
-
void
PropertyProvider::SetupJustificationSpacing(bool aPostReflow)
{
@@ -3519,8 +3515,8 @@ PropertyProvider::SetupJustificationSpacing(bool aPostReflow)
mFrame->GetTrimmedOffsets(mFrag, true, aPostReflow);
end.AdvanceOriginal(trimmed.mLength);
gfxSkipCharsIterator realEnd(end);
- ComputeJustification(start.GetOriginalOffset(),
- end.GetOriginalOffset() - start.GetOriginalOffset());
+ ComputeJustification(Range(uint32_t(start.GetOriginalOffset()),
+ uint32_t(end.GetOriginalOffset())));
auto assign = mFrame->GetJustificationAssignment();
mTotalJustificationGaps =
@@ -3535,8 +3531,8 @@ PropertyProvider::SetupJustificationSpacing(bool aPostReflow)
// so its advance "width" is actually a height in vertical writing modes,
// corresponding to the inline-direction of the frame.
gfxFloat naturalWidth =
- mTextRun->GetAdvanceWidth(mStart.GetSkippedOffset(),
- GetSkippedDistance(mStart, realEnd), this);
+ mTextRun->GetAdvanceWidth(Range(mStart.GetSkippedOffset(),
+ realEnd.GetSkippedOffset()), this);
if (mFrame->GetStateBits() & TEXT_HYPHEN_BREAK) {
naturalWidth += GetHyphenWidth();
}
@@ -5223,8 +5219,7 @@ nsTextFrame::UpdateTextEmphasis(WritingMode aWM, PropertyProvider& aProvider)
EmphasisMarkInfo* info = new EmphasisMarkInfo;
info->textRun =
GenerateTextRunForEmphasisMarks(this, fm, aWM, styleText);
- info->advance =
- info->textRun->GetAdvanceWidth(0, info->textRun->GetLength(), nullptr);
+ info->advance = info->textRun->GetAdvanceWidth();
// Calculate the baseline offset
LogicalSide side = styleText->TextEmphasisSide(aWM);
@@ -5780,26 +5775,24 @@ public:
* for RTL)
*/
SelectionIterator(SelectionDetails** aSelectionDetails,
- int32_t aStart, int32_t aLength,
- PropertyProvider& aProvider, gfxTextRun* aTextRun,
- gfxFloat aXOffset);
+ gfxTextRun::Range aRange, PropertyProvider& aProvider,
+ gfxTextRun* aTextRun, gfxFloat aXOffset);
/**
* Returns the next segment of uniformly selected (or not) text.
* @param aXOffset the offset from the origin of the frame to the start
* of the text (the left baseline origin for LTR, the right baseline origin
* for RTL)
- * @param aOffset the transformed string offset of the text for this segment
- * @param aLength the transformed string length of the text for this segment
+ * @param aRange the transformed string range of the text for this segment
* @param aHyphenWidth if a hyphen is to be rendered after the text, the
* width of the hyphen, otherwise zero
* @param aType the selection type for this segment
* @param aStyle the selection style for this segment
* @return false if there are no more segments
*/
- bool GetNextSegment(gfxFloat* aXOffset, uint32_t* aOffset, uint32_t* aLength,
- gfxFloat* aHyphenWidth, SelectionType* aType,
- TextRangeStyle* aStyle);
+ bool GetNextSegment(gfxFloat* aXOffset, gfxTextRun::Range* aRange,
+ gfxFloat* aHyphenWidth, SelectionType* aType,
+ TextRangeStyle* aStyle);
void UpdateWithAdvance(gfxFloat aAdvance) {
mXOffset += aAdvance*mTextRun->GetDirection();
}
@@ -5809,33 +5802,34 @@ private:
PropertyProvider& mProvider;
gfxTextRun* mTextRun;
gfxSkipCharsIterator mIterator;
- int32_t mOriginalStart;
- int32_t mOriginalEnd;
+ gfxTextRun::Range mOriginalRange;
gfxFloat mXOffset;
};
SelectionIterator::SelectionIterator(SelectionDetails** aSelectionDetails,
- int32_t aStart, int32_t aLength, PropertyProvider& aProvider,
- gfxTextRun* aTextRun, gfxFloat aXOffset)
+ gfxTextRun::Range aRange,
+ PropertyProvider& aProvider,
+ gfxTextRun* aTextRun, gfxFloat aXOffset)
: mSelectionDetails(aSelectionDetails), mProvider(aProvider),
mTextRun(aTextRun), mIterator(aProvider.GetStart()),
- mOriginalStart(aStart), mOriginalEnd(aStart + aLength),
- mXOffset(aXOffset)
+ mOriginalRange(aRange), mXOffset(aXOffset)
{
- mIterator.SetOriginalOffset(aStart);
+ mIterator.SetOriginalOffset(aRange.start);
}
bool SelectionIterator::GetNextSegment(gfxFloat* aXOffset,
- uint32_t* aOffset, uint32_t* aLength, gfxFloat* aHyphenWidth,
- SelectionType* aType, TextRangeStyle* aStyle)
+ gfxTextRun::Range* aRange,
+ gfxFloat* aHyphenWidth,
+ SelectionType* aType,
+ TextRangeStyle* aStyle)
{
- if (mIterator.GetOriginalOffset() >= mOriginalEnd)
+ if (mIterator.GetOriginalOffset() >= int32_t(mOriginalRange.end))
return false;
// save offset into transformed string now
uint32_t runOffset = mIterator.GetSkippedOffset();
- int32_t index = mIterator.GetOriginalOffset() - mOriginalStart;
+ uint32_t index = mIterator.GetOriginalOffset() - mOriginalRange.start;
SelectionDetails* sdptr = mSelectionDetails[index];
SelectionType type =
sdptr ? sdptr->mType : nsISelectionController::SELECTION_NONE;
@@ -5843,14 +5837,14 @@ bool SelectionIterator::GetNextSegment(gfxFloat* aXOffset,
if (sdptr) {
style = sdptr->mTextRangeStyle;
}
- for (++index; mOriginalStart + index < mOriginalEnd; ++index) {
+ for (++index; index < mOriginalRange.Length(); ++index) {
if (sdptr != mSelectionDetails[index])
break;
}
- mIterator.SetOriginalOffset(index + mOriginalStart);
+ mIterator.SetOriginalOffset(index + mOriginalRange.start);
// Advance to the next cluster boundary
- while (mIterator.GetOriginalOffset() < mOriginalEnd &&
+ while (mIterator.GetOriginalOffset() < int32_t(mOriginalRange.end) &&
!mIterator.IsOriginalCharSkipped() &&
!mTextRun->IsClusterStart(mIterator.GetSkippedOffset())) {
mIterator.AdvanceOriginal(1);
@@ -5858,11 +5852,12 @@ bool SelectionIterator::GetNextSegment(gfxFloat* aXOffset,
bool haveHyphenBreak =
(mProvider.GetFrame()->GetStateBits() & TEXT_HYPHEN_BREAK) != 0;
- *aOffset = runOffset;
- *aLength = mIterator.GetSkippedOffset() - runOffset;
+ aRange->start = runOffset;
+ aRange->end = mIterator.GetSkippedOffset();
*aXOffset = mXOffset;
*aHyphenWidth = 0;
- if (mIterator.GetOriginalOffset() == mOriginalEnd && haveHyphenBreak) {
+ if (mIterator.GetOriginalOffset() == int32_t(mOriginalRange.end) &&
+ haveHyphenBreak) {
*aHyphenWidth = mProvider.GetHyphenWidth();
}
*aType = type;
@@ -5883,8 +5878,7 @@ AddHyphenToMetrics(nsTextFrame* aTextFrame, gfxTextRun* aBaseTextRun,
return;
gfxTextRun::Metrics hyphenMetrics =
- hyphenTextRun->MeasureText(0, hyphenTextRun->GetLength(), aBoundingBoxType,
- aDrawTarget, nullptr);
+ hyphenTextRun->MeasureText(aBoundingBoxType, aDrawTarget);
if (aTextFrame->GetWritingMode().IsLineInverted()) {
hyphenMetrics.mBoundingBox.y = -hyphenMetrics.mBoundingBox.YMost();
}
@@ -5892,7 +5886,7 @@ AddHyphenToMetrics(nsTextFrame* aTextFrame, gfxTextRun* aBaseTextRun,
}
void
-nsTextFrame::PaintOneShadow(uint32_t aOffset, uint32_t aLength,
+nsTextFrame::PaintOneShadow(Range aRange,
nsCSSShadowItem* aShadowDetails,
PropertyProvider* aProvider, const nsRect& aDirtyRect,
const gfxPoint& aFramePt, const gfxPoint& aTextBaselinePt,
@@ -5960,14 +5954,19 @@ nsTextFrame::PaintOneShadow(uint32_t aOffset, uint32_t aLength,
// Remember that the box blur context has a device offset on it, so we don't need to
// translate any coordinates to fit on the surface.
gfxFloat advanceWidth;
- gfxRect dirtyRect(aDirtyRect.x, aDirtyRect.y,
- aDirtyRect.width, aDirtyRect.height);
- DrawText(shadowContext, dirtyRect, aFramePt + shadowOffset,
- aTextBaselinePt + shadowOffset, aOffset, aLength, *aProvider,
- nsTextPaintStyle(this),
- aCtx == shadowContext ? shadowColor : NS_RGB(0, 0, 0), aClipEdges,
- advanceWidth, (GetStateBits() & TEXT_HYPHEN_BREAK) != 0,
- decorationOverrideColor);
+ nsTextPaintStyle textPaintStyle(this);
+ DrawTextParams params(shadowContext);
+ params.advanceWidth = &advanceWidth;
+ params.dirtyRect = gfxRect(aDirtyRect.x, aDirtyRect.y,
+ aDirtyRect.width, aDirtyRect.height);
+ params.framePt = aFramePt + shadowOffset;
+ params.provider = aProvider;
+ params.textStyle = &textPaintStyle;
+ params.textColor = aCtx == shadowContext ? shadowColor : NS_RGB(0, 0, 0);
+ params.clipEdges = &aClipEdges;
+ params.drawSoftHyphen = (GetStateBits() & TEXT_HYPHEN_BREAK) != 0;
+ params.decorationOverrideColor = decorationOverrideColor;
+ DrawText(aRange, aTextBaselinePt + shadowOffset, params);
contextBoxBlur.DoPaint();
aCtx->Restore();
@@ -5980,7 +5979,7 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx,
const gfxPoint& aFramePt, const gfxPoint& aTextBaselinePt,
const gfxRect& aDirtyRect,
PropertyProvider& aProvider,
- uint32_t aContentOffset, uint32_t aContentLength,
+ Range aContentRange,
nsTextPaintStyle& aTextPaintStyle, SelectionDetails* aDetails,
SelectionType* aAllTypes,
const nsCharClipDisplayItem::ClipEdges& aClipEdges,
@@ -5989,22 +5988,22 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx,
// Figure out which selections control the colors to use for each character.
AutoTArray prevailingSelectionsBuffer;
SelectionDetails** prevailingSelections =
- prevailingSelectionsBuffer.AppendElements(aContentLength, fallible);
+ prevailingSelectionsBuffer.AppendElements(aContentRange.Length(), fallible);
if (!prevailingSelections) {
return false;
}
SelectionType allTypes = 0;
- for (uint32_t i = 0; i < aContentLength; ++i) {
+ for (uint32_t i = 0; i < aContentRange.Length(); ++i) {
prevailingSelections[i] = nullptr;
}
SelectionDetails *sdptr = aDetails;
bool anyBackgrounds = false;
while (sdptr) {
- int32_t start = std::max(0, sdptr->mStart - int32_t(aContentOffset));
- int32_t end = std::min(int32_t(aContentLength),
- sdptr->mEnd - int32_t(aContentOffset));
+ int32_t start = std::max(0, sdptr->mStart - int32_t(aContentRange.start));
+ int32_t end = std::min(int32_t(aContentRange.Length()),
+ sdptr->mEnd - int32_t(aContentRange.start));
SelectionType type = sdptr->mType;
if (start < end) {
allTypes |= type;
@@ -6037,23 +6036,23 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx,
const gfxFloat startIOffset = vertical ?
aTextBaselinePt.y - aFramePt.y : aTextBaselinePt.x - aFramePt.x;
gfxFloat iOffset, hyphenWidth;
- uint32_t offset, length; // in transformed string
+ Range range; // in transformed string
SelectionType type;
TextRangeStyle rangeStyle;
// Draw background colors
if (anyBackgrounds) {
int32_t appUnitsPerDevPixel = aTextPaintStyle.PresContext()->AppUnitsPerDevPixel();
LayoutDeviceRect dirtyRect = AppUnitGfxRectToDevRect(aDirtyRect, appUnitsPerDevPixel);
- SelectionIterator iterator(prevailingSelections, aContentOffset, aContentLength,
+ SelectionIterator iterator(prevailingSelections, aContentRange,
aProvider, mTextRun, startIOffset);
- while (iterator.GetNextSegment(&iOffset, &offset, &length, &hyphenWidth,
+ while (iterator.GetNextSegment(&iOffset, &range, &hyphenWidth,
&type, &rangeStyle)) {
nscolor foreground, background;
GetSelectionTextColors(type, aTextPaintStyle, rangeStyle,
&foreground, &background);
// Draw background color
gfxFloat advance = hyphenWidth +
- mTextRun->GetAdvanceWidth(offset, length, &aProvider);
+ mTextRun->GetAdvanceWidth(range, &aProvider);
if (NS_GET_A(background) > 0) {
gfxRect bgRect;
gfxFloat offs = iOffset - (mTextRun->IsInlineReversed() ? advance : 0);
@@ -6071,14 +6070,24 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx,
iterator.UpdateWithAdvance(advance);
}
}
+
+ gfxFloat advance;
+ DrawTextParams params(aCtx);
+ params.dirtyRect = aDirtyRect;
+ params.framePt = aFramePt;
+ params.provider = &aProvider;
+ params.textStyle = &aTextPaintStyle;
+ params.clipEdges = &aClipEdges;
+ params.advanceWidth = &advance;
+ params.callbacks = aCallbacks;
// Draw text
const nsStyleText* textStyle = StyleText();
nsRect dirtyRect(aDirtyRect.x, aDirtyRect.y,
aDirtyRect.width, aDirtyRect.height);
- SelectionIterator iterator(prevailingSelections, aContentOffset, aContentLength,
+ SelectionIterator iterator(prevailingSelections, aContentRange,
aProvider, mTextRun, startIOffset);
- while (iterator.GetNextSegment(&iOffset, &offset, &length, &hyphenWidth,
+ while (iterator.GetNextSegment(&iOffset, &range, &hyphenWidth,
&type, &rangeStyle)) {
nscolor foreground, background;
GetSelectionTextColors(type, aTextPaintStyle, rangeStyle,
@@ -6094,18 +6103,17 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx,
if (shadow) {
nscoord startEdge = iOffset;
if (mTextRun->IsInlineReversed()) {
- startEdge -= mTextRun->GetAdvanceWidth(offset, length, &aProvider) +
- hyphenWidth;
+ startEdge -= hyphenWidth +
+ mTextRun->GetAdvanceWidth(range, &aProvider);
}
- PaintShadows(shadow, offset, length, dirtyRect, aFramePt, textBaselinePt,
+ PaintShadows(shadow, range, dirtyRect, aFramePt, textBaselinePt,
startEdge, aProvider, foreground, aClipEdges, aCtx);
}
// Draw text segment
- gfxFloat advance;
- DrawText(aCtx, aDirtyRect, aFramePt, textBaselinePt,
- offset, length, aProvider, aTextPaintStyle, foreground, aClipEdges,
- advance, hyphenWidth > 0, nullptr, nullptr, aCallbacks);
+ params.textColor = foreground;
+ params.drawSoftHyphen = hyphenWidth > 0;
+ DrawText(range, textBaselinePt, params);
advance += hyphenWidth;
iterator.UpdateWithAdvance(advance);
}
@@ -6116,8 +6124,7 @@ void
nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx,
const gfxPoint& aFramePt,
const gfxPoint& aTextBaselinePt, const gfxRect& aDirtyRect,
- PropertyProvider& aProvider,
- uint32_t aContentOffset, uint32_t aContentLength,
+ PropertyProvider& aProvider, Range aContentRange,
nsTextPaintStyle& aTextPaintStyle, SelectionDetails* aDetails,
SelectionType aSelectionType,
nsTextFrame::DrawPathCallbacks* aCallbacks)
@@ -6129,20 +6136,20 @@ nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx,
// Figure out which characters will be decorated for this selection.
AutoTArray selectedCharsBuffer;
SelectionDetails** selectedChars =
- selectedCharsBuffer.AppendElements(aContentLength, fallible);
+ selectedCharsBuffer.AppendElements(aContentRange.Length(), fallible);
if (!selectedChars) {
return;
}
- for (uint32_t i = 0; i < aContentLength; ++i) {
+ for (uint32_t i = 0; i < aContentRange.Length(); ++i) {
selectedChars[i] = nullptr;
}
SelectionDetails *sdptr = aDetails;
while (sdptr) {
if (sdptr->mType == aSelectionType) {
- int32_t start = std::max(0, sdptr->mStart - int32_t(aContentOffset));
- int32_t end = std::min(int32_t(aContentLength),
- sdptr->mEnd - int32_t(aContentOffset));
+ int32_t start = std::max(0, sdptr->mStart - int32_t(aContentRange.start));
+ int32_t end = std::min(int32_t(aContentRange.Length()),
+ sdptr->mEnd - int32_t(aContentRange.start));
for (int32_t i = start; i < end; ++i) {
selectedChars[i] = sdptr;
}
@@ -6169,10 +6176,10 @@ nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx,
gfxFloat startIOffset =
verticalRun ? aTextBaselinePt.y - aFramePt.y : aTextBaselinePt.x - aFramePt.x;
- SelectionIterator iterator(selectedChars, aContentOffset, aContentLength,
+ SelectionIterator iterator(selectedChars, aContentRange,
aProvider, mTextRun, startIOffset);
gfxFloat iOffset, hyphenWidth;
- uint32_t offset, length;
+ Range range;
int32_t app = aTextPaintStyle.PresContext()->AppUnitsPerDevPixel();
// XXX aTextBaselinePt is in AppUnits, shouldn't it be nsFloatPoint?
gfxPoint pt;
@@ -6186,10 +6193,10 @@ nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx,
gfxFloat decorationOffsetDir = mTextRun->IsSidewaysLeft() ? -1.0 : 1.0;
SelectionType type;
TextRangeStyle selectedStyle;
- while (iterator.GetNextSegment(&iOffset, &offset, &length, &hyphenWidth,
+ while (iterator.GetNextSegment(&iOffset, &range, &hyphenWidth,
&type, &selectedStyle)) {
gfxFloat advance = hyphenWidth +
- mTextRun->GetAdvanceWidth(offset, length, &aProvider);
+ mTextRun->GetAdvanceWidth(range, &aProvider);
if (type == aSelectionType) {
if (verticalRun) {
pt.y = (aFramePt.y + iOffset -
@@ -6215,7 +6222,7 @@ nsTextFrame::PaintTextWithSelection(gfxContext* aCtx,
const gfxPoint& aFramePt,
const gfxPoint& aTextBaselinePt, const gfxRect& aDirtyRect,
PropertyProvider& aProvider,
- uint32_t aContentOffset, uint32_t aContentLength,
+ Range aContentRange,
nsTextPaintStyle& aTextPaintStyle,
const nsCharClipDisplayItem::ClipEdges& aClipEdges,
gfxTextContextPaint* aContextPaint,
@@ -6230,7 +6237,7 @@ nsTextFrame::PaintTextWithSelection(gfxContext* aCtx,
SelectionType allTypes;
if (!PaintTextWithSelectionColors(aCtx, aFramePt, aTextBaselinePt, aDirtyRect,
- aProvider, aContentOffset, aContentLength,
+ aProvider, aContentRange,
aTextPaintStyle, details, &allTypes,
aClipEdges, aCallbacks)) {
DestroySelectionDetails(details);
@@ -6249,9 +6256,8 @@ nsTextFrame::PaintTextWithSelection(gfxContext* aCtx,
// (there might not be any for this type but that's OK,
// PaintTextSelectionDecorations will exit early).
PaintTextSelectionDecorations(aCtx, aFramePt, aTextBaselinePt, aDirtyRect,
- aProvider, aContentOffset, aContentLength,
- aTextPaintStyle, details, type,
- aCallbacks);
+ aProvider, aContentRange, aTextPaintStyle,
+ details, type, aCallbacks);
}
}
@@ -6262,9 +6268,9 @@ nsTextFrame::PaintTextWithSelection(gfxContext* aCtx,
void
nsTextFrame::DrawEmphasisMarks(gfxContext* aContext, WritingMode aWM,
const gfxPoint& aTextBaselinePt,
- uint32_t aOffset, uint32_t aLength,
+ Range aRange,
const nscolor* aDecorationOverrideColor,
- PropertyProvider& aProvider)
+ PropertyProvider* aProvider)
{
const auto info = Properties().Get(EmphasisMarkProperty());
if (!info) {
@@ -6285,7 +6291,7 @@ nsTextFrame::DrawEmphasisMarks(gfxContext* aContext, WritingMode aWM,
}
}
mTextRun->DrawEmphasisMarks(aContext, info->textRun, info->advance,
- pt, aOffset, aLength, &aProvider);
+ pt, aRange, aProvider);
}
nscolor
@@ -6345,13 +6351,13 @@ nsTextFrame::GetCaretColorAt(int32_t aOffset)
return result;
}
-static uint32_t
-ComputeTransformedLength(PropertyProvider& aProvider)
+static gfxTextRun::Range
+ComputeTransformedRange(PropertyProvider& aProvider)
{
gfxSkipCharsIterator iter(aProvider.GetStart());
uint32_t start = iter.GetSkippedOffset();
iter.AdvanceOriginal(aProvider.GetOriginalLength());
- return iter.GetSkippedOffset() - start;
+ return gfxTextRun::Range(start, iter.GetSkippedOffset());
}
bool
@@ -6371,8 +6377,9 @@ nsTextFrame::MeasureCharClippedText(nscoord aVisIStartEdge,
// Trim trailing whitespace
provider.InitializeForDisplay(true);
- uint32_t startOffset = provider.GetStart().GetSkippedOffset();
- uint32_t maxLength = ComputeTransformedLength(provider);
+ Range range = ComputeTransformedRange(provider);
+ uint32_t startOffset = range.start;
+ uint32_t maxLength = range.Length();
return MeasureCharClippedText(provider, aVisIStartEdge, aVisIEndEdge,
&startOffset, &maxLength,
aSnappedStartEdge, aSnappedEndEdge);
@@ -6422,8 +6429,8 @@ nsTextFrame::MeasureCharClippedText(PropertyProvider& aProvider,
while (maxLength > 0) {
uint32_t clusterLength =
GetClusterLength(mTextRun, offset, maxLength, rtl);
- advanceWidth +=
- mTextRun->GetAdvanceWidth(offset, clusterLength, &aProvider);
+ advanceWidth += mTextRun->
+ GetAdvanceWidth(Range(offset, offset + clusterLength), &aProvider);
maxLength -= clusterLength;
offset += clusterLength;
if (advanceWidth >= maxAdvance) {
@@ -6441,8 +6448,8 @@ nsTextFrame::MeasureCharClippedText(PropertyProvider& aProvider,
while (maxLength > 0) {
uint32_t clusterLength =
GetClusterLength(mTextRun, offset, maxLength, rtl);
- gfxFloat nextAdvance = advanceWidth +
- mTextRun->GetAdvanceWidth(offset, clusterLength, &aProvider);
+ gfxFloat nextAdvance = advanceWidth + mTextRun->GetAdvanceWidth(
+ Range(offset, offset + clusterLength), &aProvider);
if (nextAdvance > maxAdvance) {
break;
}
@@ -6461,7 +6468,7 @@ nsTextFrame::MeasureCharClippedText(PropertyProvider& aProvider,
void
nsTextFrame::PaintShadows(nsCSSShadowArray* aShadow,
- uint32_t aOffset, uint32_t aLength,
+ Range aRange,
const nsRect& aDirtyRect,
const gfxPoint& aFramePt,
const gfxPoint& aTextBaselinePt,
@@ -6476,7 +6483,7 @@ nsTextFrame::PaintShadows(nsCSSShadowArray* aShadow,
}
gfxTextRun::Metrics shadowMetrics =
- mTextRun->MeasureText(aOffset, aLength, gfxFont::LOOSE_INK_EXTENTS,
+ mTextRun->MeasureText(aRange, gfxFont::LOOSE_INK_EXTENTS,
nullptr, &aProvider);
if (GetWritingMode().IsLineInverted()) {
Swap(shadowMetrics.mAscent, shadowMetrics.mDescent);
@@ -6511,8 +6518,7 @@ nsTextFrame::PaintShadows(nsCSSShadowArray* aShadow,
}
for (uint32_t i = aShadow->Length(); i > 0; --i) {
- PaintOneShadow(aOffset, aLength,
- aShadow->ShadowAt(i - 1), &aProvider,
+ PaintOneShadow(aRange, aShadow->ShadowAt(i - 1), &aProvider,
aDirtyRect, aFramePt, aTextBaselinePt, aCtx,
aForegroundColor, aClipEdges,
aLeftEdgeOffset,
@@ -6566,8 +6572,9 @@ nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
gfxPoint(reversed ? gfxFloat(aPt.x + frameWidth) : framePt.x,
nsLayoutUtils::GetSnappedBaselineY(this, ctx, aPt.y, mAscent));
}
- uint32_t startOffset = provider.GetStart().GetSkippedOffset();
- uint32_t maxLength = ComputeTransformedLength(provider);
+ Range range = ComputeTransformedRange(provider);
+ uint32_t startOffset = range.start;
+ uint32_t maxLength = range.Length();
nscoord snappedStartEdge, snappedEndEdge;
if (!MeasureCharClippedText(provider, aItem.mVisIStartEdge, aItem.mVisIEndEdge,
&startOffset, &maxLength, &snappedStartEdge, &snappedEndEdge)) {
@@ -6589,13 +6596,12 @@ nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
if (aItem.mIsFrameSelected.value()) {
MOZ_ASSERT(aOpacity == 1.0f, "We don't support opacity with selections!");
gfxSkipCharsIterator tmp(provider.GetStart());
- int32_t contentOffset = tmp.ConvertSkippedToOriginal(startOffset);
- int32_t contentLength =
- tmp.ConvertSkippedToOriginal(startOffset + maxLength) - contentOffset;
+ Range contentRange(
+ uint32_t(tmp.ConvertSkippedToOriginal(startOffset)),
+ uint32_t(tmp.ConvertSkippedToOriginal(startOffset + maxLength)));
if (PaintTextWithSelection(ctx, framePt, textBaselinePt, dirtyRect,
- provider, contentOffset, contentLength,
- textPaintStyle, clipEdges, aContextPaint,
- aCallbacks)) {
+ provider, contentRange, textPaintStyle,
+ clipEdges, aContextPaint, aCallbacks)) {
return;
}
}
@@ -6607,99 +6613,93 @@ nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
foregroundColor = gfxColor.ToABGR();
}
+ range = Range(startOffset, startOffset + maxLength);
if (!aCallbacks) {
const nsStyleText* textStyle = StyleText();
- PaintShadows(textStyle->mTextShadow, startOffset, maxLength,
- aDirtyRect, framePt, textBaselinePt, snappedStartEdge, provider,
- foregroundColor, clipEdges, ctx);
+ PaintShadows(
+ textStyle->mTextShadow, range, aDirtyRect, framePt, textBaselinePt,
+ snappedStartEdge, provider, foregroundColor, clipEdges, ctx);
}
gfxFloat advanceWidth;
- DrawText(ctx, dirtyRect, framePt, textBaselinePt, startOffset, maxLength, provider,
- textPaintStyle, foregroundColor, clipEdges, advanceWidth,
- (GetStateBits() & TEXT_HYPHEN_BREAK) != 0,
- nullptr, aContextPaint, aCallbacks);
+ DrawTextParams params(ctx);
+ params.dirtyRect = dirtyRect;
+ params.framePt = framePt;
+ params.provider = &provider;
+ params.advanceWidth = &advanceWidth;
+ params.textStyle = &textPaintStyle;
+ params.textColor = foregroundColor;
+ params.clipEdges = &clipEdges;
+ params.drawSoftHyphen = (GetStateBits() & TEXT_HYPHEN_BREAK) != 0;
+ params.contextPaint = aContextPaint;
+ params.callbacks = aCallbacks;
+ DrawText(range, textBaselinePt, params);
}
static void
DrawTextRun(gfxTextRun* aTextRun,
- gfxContext* const aCtx,
const gfxPoint& aTextBaselinePt,
- uint32_t aOffset, uint32_t aLength,
- PropertyProvider* aProvider,
- nscolor aTextColor,
- gfxFloat* aAdvanceWidth,
- gfxTextContextPaint* aContextPaint,
- nsTextFrame::DrawPathCallbacks* aCallbacks)
+ gfxTextRun::Range aRange,
+ const nsTextFrame::DrawTextRunParams& aParams)
{
- DrawMode drawMode = aCallbacks ? DrawMode::GLYPH_PATH :
- DrawMode::GLYPH_FILL;
- if (aCallbacks) {
- aCallbacks->NotifyBeforeText(aTextColor);
- aTextRun->Draw(aCtx, aTextBaselinePt, drawMode, aOffset, aLength,
- aProvider, aAdvanceWidth, aContextPaint, aCallbacks);
- aCallbacks->NotifyAfterText();
+ gfxTextRun::DrawParams params(aParams.context);
+ params.drawMode = aParams.callbacks ? DrawMode::GLYPH_PATH
+ : DrawMode::GLYPH_FILL;
+ params.provider = aParams.provider;
+ params.advanceWidth = aParams.advanceWidth;
+ params.contextPaint = aParams.contextPaint;
+ params.callbacks = aParams.callbacks;
+ if (aParams.callbacks) {
+ aParams.callbacks->NotifyBeforeText(aParams.textColor);
+ aTextRun->Draw(aRange, aTextBaselinePt, params);
+ aParams.callbacks->NotifyAfterText();
} else {
- aCtx->SetColor(Color::FromABGR(aTextColor));
- aTextRun->Draw(aCtx, aTextBaselinePt, drawMode, aOffset, aLength,
- aProvider, aAdvanceWidth, aContextPaint);
+ aParams.context->SetColor(Color::FromABGR(aParams.textColor));
+ aTextRun->Draw(aRange, aTextBaselinePt, params);
}
}
void
-nsTextFrame::DrawTextRun(gfxContext* const aCtx,
- const gfxPoint& aTextBaselinePt,
- uint32_t aOffset, uint32_t aLength,
- PropertyProvider& aProvider,
- nscolor aTextColor,
- gfxFloat& aAdvanceWidth,
- bool aDrawSoftHyphen,
- gfxTextContextPaint* aContextPaint,
- nsTextFrame::DrawPathCallbacks* aCallbacks)
+nsTextFrame::DrawTextRun(Range aRange, const gfxPoint& aTextBaselinePt,
+ const DrawTextRunParams& aParams)
{
- ::DrawTextRun(mTextRun, aCtx, aTextBaselinePt, aOffset, aLength, &aProvider,
- aTextColor, &aAdvanceWidth, aContextPaint, aCallbacks);
+ MOZ_ASSERT(aParams.advanceWidth, "Must provide advanceWidth");
+ ::DrawTextRun(mTextRun, aTextBaselinePt, aRange, aParams);
- if (aDrawSoftHyphen) {
+ if (aParams.drawSoftHyphen) {
// Don't use ctx as the context, because we need a reference context here,
// ctx may be transformed.
nsAutoPtr hyphenTextRun(GetHyphenTextRun(mTextRun, nullptr, this));
if (hyphenTextRun.get()) {
// For right-to-left text runs, the soft-hyphen is positioned at the left
// of the text, minus its own width
- gfxFloat hyphenBaselineX = aTextBaselinePt.x + mTextRun->GetDirection() * aAdvanceWidth -
- (mTextRun->IsRightToLeft() ? hyphenTextRun->GetAdvanceWidth(0, hyphenTextRun->GetLength(), nullptr) : 0);
- ::DrawTextRun(hyphenTextRun.get(), aCtx,
+ gfxFloat hyphenBaselineX = aTextBaselinePt.x +
+ mTextRun->GetDirection() * (*aParams.advanceWidth) -
+ (mTextRun->IsRightToLeft() ? hyphenTextRun->GetAdvanceWidth() : 0);
+ DrawTextRunParams params = aParams;
+ params.provider = nullptr;
+ params.advanceWidth = nullptr;
+ ::DrawTextRun(hyphenTextRun.get(),
gfxPoint(hyphenBaselineX, aTextBaselinePt.y),
- 0, hyphenTextRun->GetLength(),
- nullptr, aTextColor, nullptr, aContextPaint, aCallbacks);
+ Range(hyphenTextRun.get()), params);
}
}
}
void
-nsTextFrame::DrawTextRunAndDecorations(
- gfxContext* const aCtx, const gfxRect& aDirtyRect,
- const gfxPoint& aFramePt, const gfxPoint& aTextBaselinePt,
- uint32_t aOffset, uint32_t aLength,
- PropertyProvider& aProvider,
- const nsTextPaintStyle& aTextStyle,
- nscolor aTextColor,
- const nsCharClipDisplayItem::ClipEdges& aClipEdges,
- gfxFloat& aAdvanceWidth,
- bool aDrawSoftHyphen,
- const TextDecorations& aDecorations,
- const nscolor* const aDecorationOverrideColor,
- gfxTextContextPaint* aContextPaint,
- nsTextFrame::DrawPathCallbacks* aCallbacks)
+nsTextFrame::DrawTextRunAndDecorations(Range aRange,
+ const gfxPoint& aTextBaselinePt,
+ const DrawTextParams& aParams,
+ const TextDecorations& aDecorations)
{
- const gfxFloat app = aTextStyle.PresContext()->AppUnitsPerDevPixel();
+ const gfxFloat app =
+ aParams.textStyle->PresContext()->AppUnitsPerDevPixel();
bool verticalRun = mTextRun->IsVertical();
bool useVerticalMetrics = verticalRun && mTextRun->UseCenterBaseline();
// XXX aFramePt is in AppUnits, shouldn't it be nsFloatPoint?
- nscoord x = NSToCoordRound(aFramePt.x);
- nscoord y = NSToCoordRound(aFramePt.y);
+ nscoord x = NSToCoordRound(aParams.framePt.x);
+ nscoord y = NSToCoordRound(aParams.framePt.y);
// 'measure' here is textrun-relative, so for a horizontal run it's the
// width, while for a vertical run it's the height of the decoration
@@ -6707,9 +6707,9 @@ nsTextFrame::DrawTextRunAndDecorations(
nscoord measure = verticalRun ? frameSize.height : frameSize.width;
if (verticalRun) {
- aClipEdges.Intersect(&y, &measure);
+ aParams.clipEdges->Intersect(&y, &measure);
} else {
- aClipEdges.Intersect(&x, &measure);
+ aParams.clipEdges->Intersect(&x, &measure);
}
// decPt is the physical point where the decoration is to be drawn,
@@ -6723,7 +6723,7 @@ nsTextFrame::DrawTextRunAndDecorations(
gfxFloat ascent = gfxFloat(mAscent) / app;
// The starting edge of the frame in block direction
- gfxFloat frameBStart = verticalRun ? aFramePt.x : aFramePt.y;
+ gfxFloat frameBStart = verticalRun ? aParams.framePt.x : aParams.framePt.y;
// In vertical-rl mode, block coordinates are measured from the right,
// so we need to adjust here.
@@ -6733,8 +6733,10 @@ nsTextFrame::DrawTextRunAndDecorations(
ascent = -ascent;
}
- gfxRect dirtyRect(aDirtyRect.x / app, aDirtyRect.y / app,
- aDirtyRect.Width() / app, aDirtyRect.Height() / app);
+ gfxRect dirtyRect(aParams.dirtyRect.x / app,
+ aParams.dirtyRect.y / app,
+ aParams.dirtyRect.Width() / app,
+ aParams.dirtyRect.Height() / app);
nscoord inflationMinFontSize =
nsLayoutUtils::InflationMinFontSizeFor(this);
@@ -6759,11 +6761,11 @@ nsTextFrame::DrawTextRunAndDecorations(
decSize.height = metrics.underlineSize;
bCoord = (frameBStart - dec.mBaselineOffset) / app;
- PaintDecorationLine(aCtx, dirtyRect, dec.mColor,
- aDecorationOverrideColor, decPt, 0.0, decSize, ascent,
+ PaintDecorationLine(aParams.context, dirtyRect, dec.mColor,
+ aParams.decorationOverrideColor, decPt, 0.0, decSize, ascent,
decorationOffsetDir * metrics.underlineOffset,
NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
- dec.mStyle, eNormalDecoration, aCallbacks, verticalRun);
+ dec.mStyle, eNormalDecoration, aParams.callbacks, verticalRun);
}
// Overlines
for (uint32_t i = aDecorations.mOverlines.Length(); i-- > 0; ) {
@@ -6781,21 +6783,20 @@ nsTextFrame::DrawTextRunAndDecorations(
decSize.height = metrics.underlineSize;
bCoord = (frameBStart - dec.mBaselineOffset) / app;
- PaintDecorationLine(aCtx, dirtyRect, dec.mColor,
- aDecorationOverrideColor, decPt, 0.0, decSize, ascent,
+ PaintDecorationLine(aParams.context, dirtyRect, dec.mColor,
+ aParams.decorationOverrideColor, decPt, 0.0, decSize, ascent,
decorationOffsetDir * metrics.maxAscent,
NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, dec.mStyle,
- eNormalDecoration, aCallbacks, verticalRun);
+ eNormalDecoration, aParams.callbacks, verticalRun);
}
// CSS 2.1 mandates that text be painted after over/underlines, and *then*
// line-throughs
- DrawTextRun(aCtx, aTextBaselinePt, aOffset, aLength, aProvider, aTextColor,
- aAdvanceWidth, aDrawSoftHyphen, aContextPaint, aCallbacks);
+ DrawTextRun(aRange, aTextBaselinePt, aParams);
// Emphasis marks
- DrawEmphasisMarks(aCtx, wm, aTextBaselinePt, aOffset, aLength,
- aDecorationOverrideColor, aProvider);
+ DrawEmphasisMarks(aParams.context, wm, aTextBaselinePt, aRange,
+ aParams.decorationOverrideColor, aParams.provider);
// Line-throughs
for (uint32_t i = aDecorations.mStrikes.Length(); i-- > 0; ) {
@@ -6813,46 +6814,31 @@ nsTextFrame::DrawTextRunAndDecorations(
decSize.height = metrics.strikeoutSize;
bCoord = (frameBStart - dec.mBaselineOffset) / app;
- PaintDecorationLine(aCtx, dirtyRect, dec.mColor,
- aDecorationOverrideColor, decPt, 0.0, decSize, ascent,
+ PaintDecorationLine(aParams.context, dirtyRect, dec.mColor,
+ aParams.decorationOverrideColor, decPt, 0.0, decSize, ascent,
decorationOffsetDir * metrics.strikeoutOffset,
NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH,
- dec.mStyle, eNormalDecoration, aCallbacks, verticalRun);
+ dec.mStyle, eNormalDecoration, aParams.callbacks, verticalRun);
}
}
void
-nsTextFrame::DrawText(
- gfxContext* const aCtx, const gfxRect& aDirtyRect,
- const gfxPoint& aFramePt, const gfxPoint& aTextBaselinePt,
- uint32_t aOffset, uint32_t aLength,
- PropertyProvider& aProvider,
- const nsTextPaintStyle& aTextStyle,
- nscolor aTextColor,
- const nsCharClipDisplayItem::ClipEdges& aClipEdges,
- gfxFloat& aAdvanceWidth,
- bool aDrawSoftHyphen,
- const nscolor* const aDecorationOverrideColor,
- gfxTextContextPaint* aContextPaint,
- nsTextFrame::DrawPathCallbacks* aCallbacks)
+nsTextFrame::DrawText(Range aRange, const gfxPoint& aTextBaselinePt,
+ const DrawTextParams& aParams)
{
TextDecorations decorations;
- GetTextDecorations(aTextStyle.PresContext(),
- aCallbacks ? eUnresolvedColors : eResolvedColors,
+ GetTextDecorations(aParams.textStyle->PresContext(),
+ aParams.callbacks ? eUnresolvedColors : eResolvedColors,
decorations);
// Hide text decorations if we're currently hiding @font-face fallback text
- const bool drawDecorations = !aProvider.GetFontGroup()->ShouldSkipDrawing() &&
- (decorations.HasDecorationLines() ||
- StyleText()->HasTextEmphasis());
+ const bool drawDecorations =
+ !aParams.provider->GetFontGroup()->ShouldSkipDrawing() &&
+ (decorations.HasDecorationLines() || StyleText()->HasTextEmphasis());
if (drawDecorations) {
- DrawTextRunAndDecorations(aCtx, aDirtyRect, aFramePt, aTextBaselinePt, aOffset, aLength,
- aProvider, aTextStyle, aTextColor, aClipEdges, aAdvanceWidth,
- aDrawSoftHyphen, decorations,
- aDecorationOverrideColor, aContextPaint, aCallbacks);
+ DrawTextRunAndDecorations(aRange, aTextBaselinePt, aParams, decorations);
} else {
- DrawTextRun(aCtx, aTextBaselinePt, aOffset, aLength, aProvider,
- aTextColor, aAdvanceWidth, aDrawSoftHyphen, aContextPaint, aCallbacks);
+ DrawTextRun(aRange, aTextBaselinePt, aParams);
}
}
@@ -6905,16 +6891,16 @@ nsTextFrame::IsVisibleInSelection(nsISelection* aSelection)
* the length of the prefix. Also returns the width of the prefix in aFitWidth.
*/
static uint32_t
-CountCharsFit(gfxTextRun* aTextRun, uint32_t aStart, uint32_t aLength,
+CountCharsFit(gfxTextRun* aTextRun, gfxTextRun::Range aRange,
gfxFloat aWidth, PropertyProvider* aProvider,
gfxFloat* aFitWidth)
{
uint32_t last = 0;
gfxFloat width = 0;
- for (uint32_t i = 1; i <= aLength; ++i) {
- if (i == aLength || aTextRun->IsClusterStart(aStart + i)) {
- gfxFloat nextWidth = width +
- aTextRun->GetAdvanceWidth(aStart + last, i - last, aProvider);
+ for (uint32_t i = 1; i <= aRange.Length(); ++i) {
+ if (i == aRange.Length() || aTextRun->IsClusterStart(aRange.start + i)) {
+ gfxTextRun::Range range(aRange.start + last, aRange.start + i);
+ gfxFloat nextWidth = width + aTextRun->GetAdvanceWidth(range, aProvider);
if (nextWidth > aWidth)
break;
last = i;
@@ -6954,13 +6940,13 @@ nsTextFrame::GetCharacterOffsetAtFramePointInternal(nsPoint aPoint,
? (mTextRun->IsInlineReversed() ? mRect.height - aPoint.y : aPoint.y)
: (mTextRun->IsInlineReversed() ? mRect.width - aPoint.x : aPoint.x);
gfxFloat fitWidth;
- uint32_t skippedLength = ComputeTransformedLength(provider);
+ Range skippedRange = ComputeTransformedRange(provider);
- uint32_t charsFit = CountCharsFit(mTextRun,
- provider.GetStart().GetSkippedOffset(), skippedLength, width, &provider, &fitWidth);
+ uint32_t charsFit = CountCharsFit(mTextRun, skippedRange,
+ width, &provider, &fitWidth);
int32_t selectedOffset;
- if (charsFit < skippedLength) {
+ if (charsFit < skippedRange.Length()) {
// charsFit characters fitted, but no more could fit. See if we're
// more than halfway through the cluster.. If we are, choose the next
// cluster.
@@ -6984,8 +6970,9 @@ nsTextFrame::GetCharacterOffsetAtFramePointInternal(nsPoint aPoint,
// CountCharsFit() left us in the middle of the flag; back up over the
// first character of the ligature, and adjust fitWidth accordingly.
extraCluster.AdvanceSkipped(-2); // it's a surrogate pair: 2 code units
- fitWidth -= mTextRun->GetAdvanceWidth(extraCluster.GetSkippedOffset(),
- 2, &provider);
+ fitWidth -= mTextRun->GetAdvanceWidth(
+ Range(extraCluster.GetSkippedOffset(),
+ extraCluster.GetSkippedOffset() + 2), &provider);
}
}
@@ -6994,10 +6981,10 @@ nsTextFrame::GetCharacterOffsetAtFramePointInternal(nsPoint aPoint,
provider.GetStart().GetOriginalOffset() + provider.GetOriginalLength(),
&extraClusterLastChar, allowSplitLigature);
PropertyProvider::Spacing spacing;
+ Range extraClusterRange(extraCluster.GetSkippedOffset(),
+ extraClusterLastChar.GetSkippedOffset() + 1);
gfxFloat charWidth =
- mTextRun->GetAdvanceWidth(extraCluster.GetSkippedOffset(),
- GetSkippedDistance(extraCluster, extraClusterLastChar) + 1,
- &provider, &spacing);
+ mTextRun->GetAdvanceWidth(extraClusterRange, &provider, &spacing);
charWidth -= spacing.mBefore + spacing.mAfter;
selectedOffset = !aForInsertionPoint ||
width <= fitWidth + spacing.mBefore + charWidth/2
@@ -7195,10 +7182,9 @@ nsTextFrame::GetPointFromOffset(int32_t inOffset,
FindClusterStart(mTextRun, trimmedOffset, &iter);
}
- gfxFloat advance =
- mTextRun->GetAdvanceWidth(properties.GetStart().GetSkippedOffset(),
- GetSkippedDistance(properties.GetStart(), iter),
- &properties);
+ Range range(properties.GetStart().GetSkippedOffset(),
+ iter.GetSkippedOffset());
+ gfxFloat advance = mTextRun->GetAdvanceWidth(range, &properties);
nscoord iSize = NSToCoordCeilClamped(advance);
if (mTextRun->IsVertical()) {
@@ -7900,7 +7886,7 @@ nsTextFrame::AddInlineMinISizeForFlow(nsRenderingContext *aRenderingContext,
hyphBreakBefore = hyphBuffer.AppendElements(flowEndInTextRun - start,
fallible);
if (hyphBreakBefore) {
- provider.GetHyphenationBreaks(start, flowEndInTextRun - start,
+ provider.GetHyphenationBreaks(Range(start, flowEndInTextRun),
hyphBreakBefore);
}
}
@@ -7925,9 +7911,8 @@ nsTextFrame::AddInlineMinISizeForFlow(nsRenderingContext *aRenderingContext,
}
if (i > wordStart) {
- nscoord width =
- NSToCoordCeilClamped(textRun->GetAdvanceWidth(wordStart, i - wordStart,
- &provider));
+ nscoord width = NSToCoordCeilClamped(
+ textRun->GetAdvanceWidth(Range(wordStart, i), &provider));
width = std::max(0, width);
aData->currentLine = NSCoordSaturatingAdd(aData->currentLine, width);
aData->atStartOfLine = false;
@@ -7940,10 +7925,8 @@ nsTextFrame::AddInlineMinISizeForFlow(nsRenderingContext *aRenderingContext,
aData->trailingWhitespace += width;
} else {
// Some non-whitespace so the old trailingWhitespace is no longer trailing
- nscoord wsWidth =
- NSToCoordCeilClamped(textRun->GetAdvanceWidth(trimStart,
- i - trimStart,
- &provider));
+ nscoord wsWidth = NSToCoordCeilClamped(
+ textRun->GetAdvanceWidth(Range(trimStart, i), &provider));
aData->trailingWhitespace = std::max(0, wsWidth);
}
} else {
@@ -7953,7 +7936,7 @@ nsTextFrame::AddInlineMinISizeForFlow(nsRenderingContext *aRenderingContext,
if (preformattedTab) {
PropertyProvider::Spacing spacing;
- provider.GetSpacing(i, 1, &spacing);
+ provider.GetSpacing(Range(i, i + 1), &spacing);
aData->currentLine += nscoord(spacing.mBefore);
gfxFloat afterTab =
AdvanceToNextTab(aData->currentLine, this,
@@ -8081,9 +8064,8 @@ nsTextFrame::AddInlinePrefISizeForFlow(nsRenderingContext *aRenderingContext,
}
if (i > lineStart) {
- nscoord width =
- NSToCoordCeilClamped(textRun->GetAdvanceWidth(lineStart, i - lineStart,
- &provider));
+ nscoord width = NSToCoordCeilClamped(
+ textRun->GetAdvanceWidth(Range(lineStart, i), &provider));
width = std::max(0, width);
aData->currentLine = NSCoordSaturatingAdd(aData->currentLine, width);
@@ -8095,10 +8077,8 @@ nsTextFrame::AddInlinePrefISizeForFlow(nsRenderingContext *aRenderingContext,
aData->trailingWhitespace += width;
} else {
// Some non-whitespace so the old trailingWhitespace is no longer trailing
- nscoord wsWidth =
- NSToCoordCeilClamped(textRun->GetAdvanceWidth(trimStart,
- i - trimStart,
- &provider));
+ nscoord wsWidth = NSToCoordCeilClamped(
+ textRun->GetAdvanceWidth(Range(trimStart, i), &provider));
aData->trailingWhitespace = std::max(0, wsWidth);
}
} else {
@@ -8108,7 +8088,7 @@ nsTextFrame::AddInlinePrefISizeForFlow(nsRenderingContext *aRenderingContext,
if (preformattedTab) {
PropertyProvider::Spacing spacing;
- provider.GetSpacing(i, 1, &spacing);
+ provider.GetSpacing(Range(i, i + 1), &spacing);
aData->currentLine += nscoord(spacing.mBefore);
gfxFloat afterTab =
AdvanceToNextTab(aData->currentLine, this,
@@ -8216,8 +8196,7 @@ nsTextFrame::ComputeTightBounds(DrawTarget* aDrawTarget) const
provider.InitializeForDisplay(true);
gfxTextRun::Metrics metrics =
- mTextRun->MeasureText(provider.GetStart().GetSkippedOffset(),
- ComputeTransformedLength(provider),
+ mTextRun->MeasureText(ComputeTransformedRange(provider),
gfxFont::TIGHT_HINTED_OUTLINE_EXTENTS,
aDrawTarget, &provider);
if (GetWritingMode().IsLineInverted()) {
@@ -8250,8 +8229,7 @@ nsTextFrame::GetPrefWidthTightBounds(nsRenderingContext* aContext,
provider.InitializeForMeasure();
gfxTextRun::Metrics metrics =
- mTextRun->MeasureText(provider.GetStart().GetSkippedOffset(),
- ComputeTransformedLength(provider),
+ mTextRun->MeasureText(ComputeTransformedRange(provider),
gfxFont::TIGHT_HINTED_OUTLINE_EXTENTS,
aContext->GetDrawTarget(), &provider);
// Round it like nsTextFrame::ComputeTightBounds() to ensure consistency.
@@ -9078,7 +9056,8 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
shouldSuppressLineBreak) &&
!lineContainer->IsSVGText()) {
AddStateBits(TEXT_JUSTIFICATION_ENABLED);
- provider.ComputeJustification(offset, charsFit);
+ provider.ComputeJustification(Range(uint32_t(offset),
+ uint32_t(offset + charsFit)));
aLineLayout.SetJustificationInfo(provider.GetJustificationInfo());
}
@@ -9136,13 +9115,14 @@ nsTextFrame::TrimTrailingWhiteSpace(DrawTarget* aDrawTarget)
// OK to pass null for the line container.
PropertyProvider provider(mTextRun, textStyle, frag, this, start, contentLength,
nullptr, 0, nsTextFrame::eInflated);
- delta = mTextRun->GetAdvanceWidth(trimmedEnd, endOffset - trimmedEnd, &provider);
+ delta = mTextRun->
+ GetAdvanceWidth(Range(trimmedEnd, endOffset), &provider);
result.mChanged = true;
}
}
gfxFloat advanceDelta;
- mTextRun->SetLineBreaks(trimmedStart, trimmedEnd - trimmedStart,
+ mTextRun->SetLineBreaks(Range(trimmedStart, trimmedEnd),
(GetStateBits() & TEXT_START_OF_LINE) != 0, true,
&advanceDelta);
if (advanceDelta != 0) {
@@ -9192,8 +9172,7 @@ nsTextFrame::RecomputeOverflow(nsIFrame* aBlockFrame)
provider.InitializeForDisplay(false);
gfxTextRun::Metrics textMetrics =
- mTextRun->MeasureText(provider.GetStart().GetSkippedOffset(),
- ComputeTransformedLength(provider),
+ mTextRun->MeasureText(ComputeTransformedRange(provider),
gfxFont::LOOSE_INK_EXTENTS, nullptr,
&provider);
if (GetWritingMode().IsLineInverted()) {
diff --git a/layout/generic/nsTextFrame.h b/layout/generic/nsTextFrame.h
index daad2584dd..bfe55ceefa 100644
--- a/layout/generic/nsTextFrame.h
+++ b/layout/generic/nsTextFrame.h
@@ -44,6 +44,8 @@ class nsTextFrame : public nsTextFrameBase {
typedef mozilla::TextRangeStyle TextRangeStyle;
typedef mozilla::gfx::DrawTarget DrawTarget;
typedef mozilla::gfx::Rect Rect;
+ typedef mozilla::gfx::Size Size;
+ typedef gfxTextRun::Range Range;
public:
NS_DECL_QUERYFRAME_TARGET(nsTextFrame)
@@ -403,6 +405,30 @@ public:
virtual void NotifySelectionDecorationLinePathEmitted() { }
};
+ struct DrawTextRunParams
+ {
+ gfxContext* context;
+ PropertyProvider* provider = nullptr;
+ gfxFloat* advanceWidth = nullptr;
+ gfxTextContextPaint* contextPaint = nullptr;
+ DrawPathCallbacks* callbacks = nullptr;
+ nscolor textColor = NS_RGBA(0, 0, 0, 0);
+ bool drawSoftHyphen = false;
+ explicit DrawTextRunParams(gfxContext* aContext)
+ : context(aContext) {}
+ };
+
+ struct DrawTextParams : DrawTextRunParams
+ {
+ gfxPoint framePt;
+ gfxRect dirtyRect;
+ const nsTextPaintStyle* textStyle = nullptr;
+ const nsCharClipDisplayItem::ClipEdges* clipEdges = nullptr;
+ const nscolor* decorationOverrideColor = nullptr;
+ explicit DrawTextParams(gfxContext* aContext)
+ : DrawTextRunParams(aContext) {}
+ };
+
// Primary frame paint method called from nsDisplayText. Can also be used
// to generate paths rather than paint the frame's text by passing a callback
// object. The private DrawText() is what applies the text to a graphics
@@ -420,8 +446,7 @@ public:
const gfxPoint& aTextBaselinePt,
const gfxRect& aDirtyRect,
PropertyProvider& aProvider,
- uint32_t aContentOffset,
- uint32_t aContentLength,
+ Range aRange,
nsTextPaintStyle& aTextPaintStyle,
const nsCharClipDisplayItem::ClipEdges& aClipEdges,
gfxTextContextPaint* aContextPaint,
@@ -436,8 +461,7 @@ public:
const gfxPoint& aTextBaselinePt,
const gfxRect& aDirtyRect,
PropertyProvider& aProvider,
- uint32_t aContentOffset,
- uint32_t aContentLength,
+ Range aContentRange,
nsTextPaintStyle& aTextPaintStyle,
SelectionDetails* aDetails,
SelectionType* aAllTypes,
@@ -449,8 +473,7 @@ public:
const gfxPoint& aTextBaselinePt,
const gfxRect& aDirtyRect,
PropertyProvider& aProvider,
- uint32_t aContentOffset,
- uint32_t aContentLength,
+ Range aContentRange,
nsTextPaintStyle& aTextPaintStyle,
SelectionDetails* aDetails,
SelectionType aSelectionType,
@@ -459,9 +482,9 @@ public:
void DrawEmphasisMarks(gfxContext* aContext,
mozilla::WritingMode aWM,
const gfxPoint& aTextBaselinePt,
- uint32_t aOffset, uint32_t aLength,
+ Range aRange,
const nscolor* aDecorationOverrideColor,
- PropertyProvider& aProvider);
+ PropertyProvider* aProvider);
virtual nscolor GetCaretColorAt(int32_t aOffset) override;
@@ -612,8 +635,7 @@ protected:
nsRect UpdateTextEmphasis(mozilla::WritingMode aWM,
PropertyProvider& aProvider);
- void PaintOneShadow(uint32_t aOffset,
- uint32_t aLength,
+ void PaintOneShadow(Range aRange,
nsCSSShadowItem* aShadowDetails,
PropertyProvider* aProvider,
const nsRect& aDirtyRect,
@@ -627,7 +649,7 @@ protected:
uint32_t aBlurFlags);
void PaintShadows(nsCSSShadowArray* aShadow,
- uint32_t aOffset, uint32_t aLength,
+ Range aRange,
const nsRect& aDirtyRect,
const gfxPoint& aFramePt,
const gfxPoint& aTextBaselinePt,
@@ -711,49 +733,15 @@ protected:
TextDecorationColorResolution aColorResolution,
TextDecorations& aDecorations);
- void DrawTextRun(gfxContext* const aCtx,
- const gfxPoint& aTextBaselinePt,
- uint32_t aOffset,
- uint32_t aLength,
- PropertyProvider& aProvider,
- nscolor aTextColor,
- gfxFloat& aAdvanceWidth,
- bool aDrawSoftHyphen,
- gfxTextContextPaint* aContextPaint,
- DrawPathCallbacks* aCallbacks);
+ void DrawTextRun(Range aRange, const gfxPoint& aTextBaselinePt,
+ const DrawTextRunParams& aParams);
- void DrawTextRunAndDecorations(gfxContext* const aCtx,
- const gfxRect& aDirtyRect,
- const gfxPoint& aFramePt,
- const gfxPoint& aTextBaselinePt,
- uint32_t aOffset,
- uint32_t aLength,
- PropertyProvider& aProvider,
- const nsTextPaintStyle& aTextStyle,
- nscolor aTextColor,
- const nsCharClipDisplayItem::ClipEdges& aClipEdges,
- gfxFloat& aAdvanceWidth,
- bool aDrawSoftHyphen,
- const TextDecorations& aDecorations,
- const nscolor* const aDecorationOverrideColor,
- gfxTextContextPaint* aContextPaint,
- DrawPathCallbacks* aCallbacks);
+ void DrawTextRunAndDecorations(Range aRange, const gfxPoint& aTextBaselinePt,
+ const DrawTextParams& aParams,
+ const TextDecorations& aDecorations);
- void DrawText(gfxContext* const aCtx,
- const gfxRect& aDirtyRect,
- const gfxPoint& aFramePt,
- const gfxPoint& aTextBaselinePt,
- uint32_t aOffset,
- uint32_t aLength,
- PropertyProvider& aProvider,
- const nsTextPaintStyle& aTextStyle,
- nscolor aTextColor,
- const nsCharClipDisplayItem::ClipEdges& aClipEdges,
- gfxFloat& aAdvanceWidth,
- bool aDrawSoftHyphen,
- const nscolor* const aDecorationOverrideColor = nullptr,
- gfxTextContextPaint* aContextPaint = nullptr,
- DrawPathCallbacks* aCallbacks = nullptr);
+ void DrawText(Range aRange, const gfxPoint& aTextBaselinePt,
+ const DrawTextParams& aParams);
// Set non empty rect to aRect, it should be overflow rect or frame rect.
// If the result rect is larger than the given rect, this returns true.
diff --git a/layout/generic/nsTextRunTransformations.cpp b/layout/generic/nsTextRunTransformations.cpp
index d5b702ddce..0b2cab9e1b 100644
--- a/layout/generic/nsTextRunTransformations.cpp
+++ b/layout/generic/nsTextRunTransformations.cpp
@@ -69,11 +69,11 @@ nsTransformedTextRun::SetCapitalization(uint32_t aStart, uint32_t aLength,
}
bool
-nsTransformedTextRun::SetPotentialLineBreaks(uint32_t aStart, uint32_t aLength,
+nsTransformedTextRun::SetPotentialLineBreaks(Range aRange,
uint8_t* aBreakBefore)
{
bool changed =
- gfxTextRun::SetPotentialLineBreaks(aStart, aLength, aBreakBefore);
+ gfxTextRun::SetPotentialLineBreaks(aRange, aBreakBefore);
if (changed) {
mNeedsRebuild = true;
}
@@ -131,7 +131,7 @@ MergeCharactersInTextRun(gfxTextRun* aDest, gfxTextRun* aSrc,
{
aDest->ResetGlyphRuns();
- gfxTextRun::GlyphRunIterator iter(aSrc, 0, aSrc->GetLength());
+ gfxTextRun::GlyphRunIterator iter(aSrc, gfxTextRun::Range(aSrc));
uint32_t offset = 0;
AutoTArray glyphs;
while (iter.NextRun()) {
@@ -658,8 +658,8 @@ nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
// (and also child will be shaped appropriately)
NS_ASSERTION(convertedString.Length() == canBreakBeforeArray.Length(),
"Dropped characters or break-before values somewhere!");
- child->SetPotentialLineBreaks(0, canBreakBeforeArray.Length(),
- canBreakBeforeArray.Elements());
+ gfxTextRun::Range range(0, uint32_t(canBreakBeforeArray.Length()));
+ child->SetPotentialLineBreaks(range, canBreakBeforeArray.Elements());
if (transformedChild) {
transformedChild->FinishSettingProperties(aRefDrawTarget, aMFR);
}
@@ -678,6 +678,6 @@ nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
// We can't steal the data because the child may be cached and stealing
// the data would break the cache.
aTextRun->ResetGlyphRuns();
- aTextRun->CopyGlyphDataFrom(child, 0, child->GetLength(), 0);
+ aTextRun->CopyGlyphDataFrom(child, gfxTextRun::Range(child), 0);
}
}
diff --git a/layout/generic/nsTextRunTransformations.h b/layout/generic/nsTextRunTransformations.h
index d1040ede7c..9fc797935e 100644
--- a/layout/generic/nsTextRunTransformations.h
+++ b/layout/generic/nsTextRunTransformations.h
@@ -130,8 +130,7 @@ public:
void SetCapitalization(uint32_t aStart, uint32_t aLength,
bool* aCapitalization);
- virtual bool SetPotentialLineBreaks(uint32_t aStart, uint32_t aLength,
- uint8_t* aBreakBefore);
+ virtual bool SetPotentialLineBreaks(Range aRange, uint8_t* aBreakBefore);
/**
* Called after SetCapitalization and SetPotentialLineBreaks
* are done and before we request any data from the textrun. Also always
diff --git a/layout/inspector/nsFontFaceList.cpp b/layout/inspector/nsFontFaceList.cpp
index 57f7413d6c..5f9b0ecb48 100644
--- a/layout/inspector/nsFontFaceList.cpp
+++ b/layout/inspector/nsFontFaceList.cpp
@@ -60,7 +60,8 @@ nsresult
nsFontFaceList::AddFontsFromTextRun(gfxTextRun* aTextRun,
uint32_t aOffset, uint32_t aLength)
{
- gfxTextRun::GlyphRunIterator iter(aTextRun, aOffset, aLength);
+ gfxTextRun::Range range(aOffset, aOffset + aLength);
+ gfxTextRun::GlyphRunIterator iter(aTextRun, range);
while (iter.NextRun()) {
gfxFontEntry *fe = iter.GetGlyphRun()->mFont->GetFontEntry();
// if we have already listed this face, just make sure the match type is
diff --git a/layout/mathml/nsMathMLChar.cpp b/layout/mathml/nsMathMLChar.cpp
index 51697a4095..28fbf4de7e 100644
--- a/layout/mathml/nsMathMLChar.cpp
+++ b/layout/mathml/nsMathMLChar.cpp
@@ -1023,9 +1023,7 @@ static nsBoundingMetrics
MeasureTextRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun)
{
gfxTextRun::Metrics metrics =
- aTextRun->MeasureText(0, aTextRun->GetLength(),
- gfxFont::TIGHT_HINTED_OUTLINE_EXTENTS,
- aDrawTarget, nullptr);
+ aTextRun->MeasureText(gfxFont::TIGHT_HINTED_OUTLINE_EXTENTS, aDrawTarget);
nsBoundingMetrics bm;
bm.leftBearing = NSToCoordFloor(metrics.mBoundingBox.X());
@@ -2150,9 +2148,8 @@ nsMathMLChar::PaintForeground(nsPresContext* aPresContext,
// draw a single glyph (base size or size variant)
// XXXfredw verify if mGlyphs[0] is non-null to workaround bug 973322.
if (mGlyphs[0]) {
- mGlyphs[0]->Draw(thebesContext, gfxPoint(0.0, mUnscaledAscent),
- DrawMode::GLYPH_FILL, 0, mGlyphs[0]->GetLength(),
- nullptr, nullptr, nullptr);
+ mGlyphs[0]->Draw(Range(mGlyphs[0]), gfxPoint(0.0, mUnscaledAscent),
+ gfxTextRun::DrawParams(thebesContext));
}
break;
case DRAW_PARTS: {
@@ -2279,6 +2276,8 @@ nsMathMLChar::PaintVertically(nsPresContext* aPresContext,
mBoundingMetrics.rightBearing - mBoundingMetrics.leftBearing;
unionRect.Inflate(oneDevPixel, oneDevPixel);
+ gfxTextRun::DrawParams params(aThebesContext);
+
/////////////////////////////////////
// draw top, middle, bottom
for (i = 0; i <= 2; ++i) {
@@ -2307,9 +2306,7 @@ nsMathMLChar::PaintVertically(nsPresContext* aPresContext,
}
if (!clipRect.IsEmpty()) {
AutoPushClipRect clip(aThebesContext, oneDevPixel, clipRect);
- mGlyphs[i]->Draw(aThebesContext, gfxPoint(dx, dy),
- DrawMode::GLYPH_FILL, 0, mGlyphs[i]->GetLength(),
- nullptr, nullptr, nullptr);
+ mGlyphs[i]->Draw(Range(mGlyphs[i]), gfxPoint(dx, dy), params);
}
}
}
@@ -2375,9 +2372,7 @@ nsMathMLChar::PaintVertically(nsPresContext* aPresContext,
clipRect.height = std::min(bm.ascent + bm.descent, fillEnd - dy);
AutoPushClipRect clip(aThebesContext, oneDevPixel, clipRect);
dy += bm.ascent;
- mGlyphs[3]->Draw(aThebesContext, gfxPoint(dx, dy),
- DrawMode::GLYPH_FILL, 0, mGlyphs[3]->GetLength(),
- nullptr, nullptr, nullptr);
+ mGlyphs[3]->Draw(Range(mGlyphs[3]), gfxPoint(dx, dy), params);
dy += bm.descent;
}
}
@@ -2453,6 +2448,8 @@ nsMathMLChar::PaintHorizontally(nsPresContext* aPresContext,
nsRect unionRect = aRect;
unionRect.Inflate(oneDevPixel, oneDevPixel);
+ gfxTextRun::DrawParams params(aThebesContext);
+
///////////////////////////
// draw left, middle, right
for (i = 0; i <= 2; ++i) {
@@ -2479,9 +2476,7 @@ nsMathMLChar::PaintHorizontally(nsPresContext* aPresContext,
}
if (!clipRect.IsEmpty()) {
AutoPushClipRect clip(aThebesContext, oneDevPixel, clipRect);
- mGlyphs[i]->Draw(aThebesContext, gfxPoint(dx, dy),
- DrawMode::GLYPH_FILL, 0, mGlyphs[i]->GetLength(),
- nullptr, nullptr, nullptr);
+ mGlyphs[i]->Draw(Range(mGlyphs[i]), gfxPoint(dx, dy), params);
}
}
}
@@ -2545,9 +2540,7 @@ nsMathMLChar::PaintHorizontally(nsPresContext* aPresContext,
clipRect.width = std::min(bm.rightBearing - bm.leftBearing, fillEnd - dx);
AutoPushClipRect clip(aThebesContext, oneDevPixel, clipRect);
dx -= bm.leftBearing;
- mGlyphs[3]->Draw(aThebesContext, gfxPoint(dx, dy),
- DrawMode::GLYPH_FILL, 0, mGlyphs[3]->GetLength(),
- nullptr, nullptr, nullptr);
+ mGlyphs[3]->Draw(Range(mGlyphs[3]), gfxPoint(dx, dy), params);
dx += bm.rightBearing;
}
}
diff --git a/layout/mathml/nsMathMLChar.h b/layout/mathml/nsMathMLChar.h
index 602d587ff8..1d3cc520e2 100644
--- a/layout/mathml/nsMathMLChar.h
+++ b/layout/mathml/nsMathMLChar.h
@@ -13,7 +13,7 @@
#include "nsRect.h"
#include "nsString.h"
#include "nsBoundingMetrics.h"
-#include "gfxFont.h"
+#include "gfxTextRun.h"
class nsGlyphTable;
class nsIFrame;
@@ -85,6 +85,7 @@ struct nsGlyphCode {
class nsMathMLChar
{
public:
+ typedef gfxTextRun::Range Range;
typedef mozilla::gfx::DrawTarget DrawTarget;
// constructor and destructor
diff --git a/layout/reftests/font-matching/reftest.list b/layout/reftests/font-matching/reftest.list
index f754fc1c52..16ee8809a9 100644
--- a/layout/reftests/font-matching/reftest.list
+++ b/layout/reftests/font-matching/reftest.list
@@ -110,3 +110,14 @@ fuzzy-if(Mulet,103,144) == italic-oblique-6.html italic-oblique-ref.html
fuzzy-if(Mulet,103,144) == italic-oblique-8.html italic-oblique-ref.html
fuzzy-if(Mulet,103,144) == italic-oblique-9.html italic-oblique-ref.html
!= italic-oblique-kinnari.html italic-oblique-kinnari-ref.html
+
+# system font generic per-language tests, only works under OSX currently
+random-if(!OSX) == system-generic-fallback-1.html system-generic-fallback-1-ref.html
+random-if(!OSX||OSX<1008) == system-generic-fallback-2.html system-generic-fallback-2-ref.html
+random-if(!OSX||OSX<1008) == system-generic-fallback-3.html system-generic-fallback-3-ref.html
+random-if(!OSX||OSX<1008) == system-generic-fallback-4.html system-generic-fallback-4-ref.html
+random-if(!OSX) != system-generic-fallback-ko.html system-generic-fallback-ja.html
+random-if(!OSX) != system-generic-fallback-zh-tw.html system-generic-fallback-ja.html
+random-if(!OSX) != system-generic-fallback-zh-cn.html system-generic-fallback-ja.html
+random-if(!OSX) != system-generic-fallback-zh-tw.html system-generic-fallback-zh-cn.html
+
diff --git a/layout/reftests/font-matching/system-generic-fallback-1-ref.html b/layout/reftests/font-matching/system-generic-fallback-1-ref.html
new file mode 100644
index 0000000000..84deb813a1
--- /dev/null
+++ b/layout/reftests/font-matching/system-generic-fallback-1-ref.html
@@ -0,0 +1,39 @@
+
+
+
+system generic linked families
+
+
+
+
+
+
+
+
+
+
+
diff --git a/layout/reftests/font-matching/system-generic-fallback-1.html b/layout/reftests/font-matching/system-generic-fallback-1.html
new file mode 100644
index 0000000000..d06d5259cb
--- /dev/null
+++ b/layout/reftests/font-matching/system-generic-fallback-1.html
@@ -0,0 +1,39 @@
+
+
+
+system generic linked families
+
+
+
+
+
+
+
+
+
+
+
diff --git a/layout/reftests/font-matching/system-generic-fallback-2-ref.html b/layout/reftests/font-matching/system-generic-fallback-2-ref.html
new file mode 100644
index 0000000000..efe6f93739
--- /dev/null
+++ b/layout/reftests/font-matching/system-generic-fallback-2-ref.html
@@ -0,0 +1,38 @@
+
+
+
+system generic linked families
+
+
+
+
+
+
+
+
+
+
+
diff --git a/layout/reftests/font-matching/system-generic-fallback-2.html b/layout/reftests/font-matching/system-generic-fallback-2.html
new file mode 100644
index 0000000000..2e1b02655c
--- /dev/null
+++ b/layout/reftests/font-matching/system-generic-fallback-2.html
@@ -0,0 +1,38 @@
+
+
+
+system generic linked families
+
+
+
+
+
+
+
+
+
+
+
diff --git a/layout/reftests/font-matching/system-generic-fallback-3-ref.html b/layout/reftests/font-matching/system-generic-fallback-3-ref.html
new file mode 100644
index 0000000000..0ddd8c5d94
--- /dev/null
+++ b/layout/reftests/font-matching/system-generic-fallback-3-ref.html
@@ -0,0 +1,38 @@
+
+
+
+system generic linked families
+
+
+
+
+
+
+
+
+
+
+
diff --git a/layout/reftests/font-matching/system-generic-fallback-3.html b/layout/reftests/font-matching/system-generic-fallback-3.html
new file mode 100644
index 0000000000..a704d234c4
--- /dev/null
+++ b/layout/reftests/font-matching/system-generic-fallback-3.html
@@ -0,0 +1,38 @@
+
+
+
+system generic linked families
+
+
+
+
+
+
+
+
+
+
+
diff --git a/layout/reftests/font-matching/system-generic-fallback-4-ref.html b/layout/reftests/font-matching/system-generic-fallback-4-ref.html
new file mode 100644
index 0000000000..5961caaf53
--- /dev/null
+++ b/layout/reftests/font-matching/system-generic-fallback-4-ref.html
@@ -0,0 +1,38 @@
+
+
+
+system generic linked families
+
+
+
+
+
+
+
+
+
+
+
diff --git a/layout/reftests/font-matching/system-generic-fallback-4.html b/layout/reftests/font-matching/system-generic-fallback-4.html
new file mode 100644
index 0000000000..d7ffee3e97
--- /dev/null
+++ b/layout/reftests/font-matching/system-generic-fallback-4.html
@@ -0,0 +1,38 @@
+
+
+
+system generic linked families
+
+
+
+
+
+
+
+
+
+
+
diff --git a/layout/reftests/font-matching/system-generic-fallback-ja.html b/layout/reftests/font-matching/system-generic-fallback-ja.html
new file mode 100644
index 0000000000..844200111f
--- /dev/null
+++ b/layout/reftests/font-matching/system-generic-fallback-ja.html
@@ -0,0 +1,33 @@
+
+
+
+system generic linked families
+
+
+
+
+
+
+
+
+
+
+
diff --git a/layout/reftests/font-matching/system-generic-fallback-ko.html b/layout/reftests/font-matching/system-generic-fallback-ko.html
new file mode 100644
index 0000000000..526ab817d8
--- /dev/null
+++ b/layout/reftests/font-matching/system-generic-fallback-ko.html
@@ -0,0 +1,33 @@
+
+
+
+system generic linked families
+
+
+
+
+
+
+
+
+
+
+
diff --git a/layout/reftests/font-matching/system-generic-fallback-zh-cn.html b/layout/reftests/font-matching/system-generic-fallback-zh-cn.html
new file mode 100644
index 0000000000..afcabb396c
--- /dev/null
+++ b/layout/reftests/font-matching/system-generic-fallback-zh-cn.html
@@ -0,0 +1,33 @@
+
+
+
+system generic linked families
+
+
+
+
+
+
+
+
+
+
+
diff --git a/layout/reftests/font-matching/system-generic-fallback-zh-tw.html b/layout/reftests/font-matching/system-generic-fallback-zh-tw.html
new file mode 100644
index 0000000000..64cc1aded5
--- /dev/null
+++ b/layout/reftests/font-matching/system-generic-fallback-zh-tw.html
@@ -0,0 +1,33 @@
+
+
+
+system generic linked families
+
+
+
+
+
+
+
+
+
+
+
diff --git a/layout/svg/SVGTextFrame.cpp b/layout/svg/SVGTextFrame.cpp
index 19ea8f8809..cbad10ef0f 100644
--- a/layout/svg/SVGTextFrame.cpp
+++ b/layout/svg/SVGTextFrame.cpp
@@ -60,34 +60,16 @@ using namespace mozilla::gfx;
* in original char indexes to skipped char indexes.
*
* @param aIterator The gfxSkipCharsIterator to use for the conversion.
- * @param aOriginalOffset The original offset (input).
- * @param aOriginalLength The original length (input).
- * @param aSkippedOffset The skipped offset (output).
- * @param aSkippedLength The skipped length (output).
+ * @param aOriginalOffset The original offset.
+ * @param aOriginalLength The original length.
*/
-static void
+static gfxTextRun::Range
ConvertOriginalToSkipped(gfxSkipCharsIterator& aIterator,
- uint32_t aOriginalOffset, uint32_t aOriginalLength,
- uint32_t& aSkippedOffset, uint32_t& aSkippedLength)
+ uint32_t aOriginalOffset, uint32_t aOriginalLength)
{
- aSkippedOffset = aIterator.ConvertOriginalToSkipped(aOriginalOffset);
+ uint32_t start = aIterator.ConvertOriginalToSkipped(aOriginalOffset);
aIterator.AdvanceOriginal(aOriginalLength);
- aSkippedLength = aIterator.GetSkippedOffset() - aSkippedOffset;
-}
-
-/**
- * Using the specified gfxSkipCharsIterator, converts an offset and length
- * in original char indexes to skipped char indexes in place.
- *
- * @param aIterator The gfxSkipCharsIterator to use for the conversion.
- * @param aOriginalOffset The offset to convert from original to skipped.
- * @param aOriginalLength The length to convert from original to skipped.
- */
-static void
-ConvertOriginalToSkipped(gfxSkipCharsIterator& aIterator,
- uint32_t& aOffset, uint32_t& aLength)
-{
- ConvertOriginalToSkipped(aIterator, aOffset, aLength, aOffset, aLength);
+ return gfxTextRun::Range(start, aIterator.GetSkippedOffset());
}
/**
@@ -157,15 +139,11 @@ GetAscentAndDescentInAppUnits(nsTextFrame* aFrame,
gfxSkipCharsIterator it = aFrame->EnsureTextRun(nsTextFrame::eInflated);
gfxTextRun* textRun = aFrame->GetTextRun(nsTextFrame::eInflated);
- uint32_t offset, length;
- ConvertOriginalToSkipped(it,
- aFrame->GetContentOffset(),
- aFrame->GetContentLength(),
- offset, length);
+ gfxTextRun::Range range = ConvertOriginalToSkipped(
+ it, aFrame->GetContentOffset(), aFrame->GetContentLength());
gfxTextRun::Metrics metrics =
- textRun->MeasureText(offset, length, gfxFont::LOOSE_INK_EXTENTS, nullptr,
- nullptr);
+ textRun->MeasureText(range, gfxFont::LOOSE_INK_EXTENTS, nullptr, nullptr);
aAscent = metrics.mAscent;
aDescent = metrics.mDescent;
@@ -342,8 +320,7 @@ GetBaselinePosition(nsTextFrame* aFrame,
{
WritingMode writingMode = aFrame->GetWritingMode();
gfxTextRun::Metrics metrics =
- aTextRun->MeasureText(0, aTextRun->GetLength(), gfxFont::LOOSE_INK_EXTENTS,
- nullptr, nullptr);
+ aTextRun->MeasureText(gfxFont::LOOSE_INK_EXTENTS, nullptr);
switch (aDominantBaseline) {
case NS_STYLE_DOMINANT_BASELINE_HANGING:
@@ -386,7 +363,7 @@ GetBaselinePosition(nsTextFrame* aFrame,
}
/**
- * For a given text run, returns the number of skipped characters that comprise
+ * For a given text run, returns the range of skipped characters that comprise
* the ligature group and/or cluster that includes the character represented
* by the specified gfxSkipCharsIterator.
*
@@ -395,8 +372,8 @@ GetBaselinePosition(nsTextFrame* aFrame,
* @param aIterator The gfxSkipCharsIterator to use for the current position
* in the text run.
*/
-static uint32_t
-ClusterLength(gfxTextRun* aTextRun, const gfxSkipCharsIterator& aIterator)
+static gfxTextRun::Range
+ClusterRange(gfxTextRun* aTextRun, const gfxSkipCharsIterator& aIterator)
{
uint32_t start = aIterator.GetSkippedOffset();
uint32_t end = start + 1;
@@ -405,7 +382,7 @@ ClusterLength(gfxTextRun* aTextRun, const gfxSkipCharsIterator& aIterator)
!aTextRun->IsClusterStart(end))) {
end++;
}
- return end - start;
+ return gfxTextRun::Range(start, end);
}
/**
@@ -482,6 +459,8 @@ namespace mozilla {
*/
struct TextRenderedRun
{
+ typedef gfxTextRun::Range Range;
+
/**
* Constructs a TextRenderedRun that is uninitialized except for mFrame
* being null.
@@ -939,17 +918,15 @@ TextRenderedRun::GetRunUserSpaceRect(nsPresContext* aContext,
gfxTextRun* textRun = mFrame->GetTextRun(nsTextFrame::eInflated);
// Get the content range for this rendered run.
- uint32_t offset, length;
- ConvertOriginalToSkipped(it, mTextFrameContentOffset, mTextFrameContentLength,
- offset, length);
- if (length == 0) {
+ Range range = ConvertOriginalToSkipped(it, mTextFrameContentOffset,
+ mTextFrameContentLength);
+ if (range.Length() == 0) {
return r;
}
// Measure that range.
gfxTextRun::Metrics metrics =
- textRun->MeasureText(offset, length, gfxFont::LOOSE_INK_EXTENTS,
- nullptr, nullptr);
+ textRun->MeasureText(range, gfxFont::LOOSE_INK_EXTENTS, nullptr, nullptr);
// Make sure it includes the font-box.
gfxRect fontBox(0, -metrics.mAscent,
metrics.mAdvanceWidth, metrics.mAscent + metrics.mDescent);
@@ -962,7 +939,7 @@ TextRenderedRun::GetRunUserSpaceRect(nsPresContext* aContext,
gfxFloat x, width;
if (aFlags & eNoHorizontalOverflow) {
x = 0.0;
- width = textRun->GetAdvanceWidth(offset, length, nullptr);
+ width = textRun->GetAdvanceWidth(range, nullptr);
} else {
x = metrics.mBoundingBox.x;
width = metrics.mBoundingBox.width;
@@ -1059,13 +1036,12 @@ TextRenderedRun::GetClipEdges(nscoord& aVisIStartEdge,
// Get the covered content offset/length for this rendered run in skipped
// characters, since that is what GetAdvanceWidth expects.
- uint32_t runOffset, runLength, frameOffset, frameLength;
- ConvertOriginalToSkipped(it, mTextFrameContentOffset, mTextFrameContentLength,
- runOffset, runLength);
+ Range runRange = ConvertOriginalToSkipped(it, mTextFrameContentOffset,
+ mTextFrameContentLength);
// Get the offset/length of the whole nsTextFrame.
- frameOffset = mFrame->GetContentOffset();
- frameLength = mFrame->GetContentLength();
+ uint32_t frameOffset = mFrame->GetContentOffset();
+ uint32_t frameLength = mFrame->GetContentLength();
// Trim the whole-nsTextFrame offset/length to remove any leading/trailing
// white space, as the nsTextFrame when painting does not include them when
@@ -1076,19 +1052,17 @@ TextRenderedRun::GetClipEdges(nscoord& aVisIStartEdge,
// Convert the trimmed whole-nsTextFrame offset/length into skipped
// characters.
- ConvertOriginalToSkipped(it, frameOffset, frameLength);
+ Range frameRange = ConvertOriginalToSkipped(it, frameOffset, frameLength);
// Measure the advance width in the text run between the start of
// frame's content and the start of the rendered run's content,
- nscoord startEdge =
- textRun->GetAdvanceWidth(frameOffset, runOffset - frameOffset, nullptr);
+ nscoord startEdge = textRun->
+ GetAdvanceWidth(Range(frameRange.start, runRange.start), nullptr);
// and between the end of the rendered run's content and the end
// of the frame's content.
- nscoord endEdge =
- textRun->GetAdvanceWidth(runOffset + runLength,
- frameOffset + frameLength - (runOffset + runLength),
- nullptr);
+ nscoord endEdge = textRun->
+ GetAdvanceWidth(Range(runRange.end, frameRange.end), nullptr);
if (textRun->IsRightToLeft()) {
aVisIStartEdge = endEdge;
@@ -1105,11 +1079,10 @@ TextRenderedRun::GetAdvanceWidth() const
gfxSkipCharsIterator it = mFrame->EnsureTextRun(nsTextFrame::eInflated);
gfxTextRun* textRun = mFrame->GetTextRun(nsTextFrame::eInflated);
- uint32_t offset, length;
- ConvertOriginalToSkipped(it, mTextFrameContentOffset, mTextFrameContentLength,
- offset, length);
+ Range range = ConvertOriginalToSkipped(it, mTextFrameContentOffset,
+ mTextFrameContentLength);
- return textRun->GetAdvanceWidth(offset, length, nullptr);
+ return textRun->GetAdvanceWidth(range, nullptr);
}
int32_t
@@ -1160,12 +1133,10 @@ TextRenderedRun::GetCharNumAtPosition(nsPresContext* aContext,
// Next check that the point lies horizontally within the left and right
// edges of the text.
- uint32_t offset, length;
- ConvertOriginalToSkipped(it, mTextFrameContentOffset, mTextFrameContentLength,
- offset, length);
+ Range range = ConvertOriginalToSkipped(it, mTextFrameContentOffset,
+ mTextFrameContentLength);
gfxFloat runAdvance =
- aContext->AppUnitsToGfxUnits(textRun->GetAdvanceWidth(offset, length,
- nullptr));
+ aContext->AppUnitsToGfxUnits(textRun->GetAdvanceWidth(range, nullptr));
gfxFloat pos = writingMode.IsVertical() ? p.y : p.x;
if (pos < 0 || pos >= runAdvance) {
@@ -1177,10 +1148,9 @@ TextRenderedRun::GetCharNumAtPosition(nsPresContext* aContext,
// support letter-spacing and word-spacing.
bool rtl = textRun->IsRightToLeft();
for (int32_t i = mTextFrameContentLength - 1; i >= 0; i--) {
- ConvertOriginalToSkipped(it, mTextFrameContentOffset, i, offset, length);
+ range = ConvertOriginalToSkipped(it, mTextFrameContentOffset, i);
gfxFloat advance =
- aContext->AppUnitsToGfxUnits(textRun->GetAdvanceWidth(offset, length,
- nullptr));
+ aContext->AppUnitsToGfxUnits(textRun->GetAdvanceWidth(range, nullptr));
if ((rtl && pos < runAdvance - advance) ||
(!rtl && pos >= advance)) {
return i;
@@ -2138,6 +2108,8 @@ TextRenderedRunIterator::First()
*/
class CharIterator
{
+ typedef gfxTextRun::Range Range;
+
public:
/**
* Values for the aFilter argument of the constructor, to indicate which
@@ -2629,12 +2601,12 @@ CharIterator::GetGlyphAdvance(nsPresContext* aContext) const
GetOriginalGlyphOffsets(offset, length);
gfxSkipCharsIterator it = TextFrame()->EnsureTextRun(nsTextFrame::eInflated);
- ConvertOriginalToSkipped(it, offset, length);
+ Range range = ConvertOriginalToSkipped(it, offset, length);
float cssPxPerDevPx = aContext->
AppUnitsToFloatCSSPixels(aContext->AppUnitsPerDevPixel());
- gfxFloat advance = mTextRun->GetAdvanceWidth(offset, length, nullptr);
+ gfxFloat advance = mTextRun->GetAdvanceWidth(range, nullptr);
return aContext->AppUnitsToGfxUnits(advance) *
mLengthAdjustScaleFactor * cssPxPerDevPx;
}
@@ -2645,8 +2617,9 @@ CharIterator::GetAdvance(nsPresContext* aContext) const
float cssPxPerDevPx = aContext->
AppUnitsToFloatCSSPixels(aContext->AppUnitsPerDevPixel());
- gfxFloat advance =
- mTextRun->GetAdvanceWidth(mSkipCharsIterator.GetSkippedOffset(), 1, nullptr);
+ uint32_t offset = mSkipCharsIterator.GetSkippedOffset();
+ gfxFloat advance = mTextRun->
+ GetAdvanceWidth(Range(offset, offset + 1), nullptr);
return aContext->AppUnitsToGfxUnits(advance) *
mLengthAdjustScaleFactor * cssPxPerDevPx;
}
@@ -2662,12 +2635,12 @@ CharIterator::GetGlyphPartialAdvance(uint32_t aPartLength,
length = aPartLength;
gfxSkipCharsIterator it = TextFrame()->EnsureTextRun(nsTextFrame::eInflated);
- ConvertOriginalToSkipped(it, offset, length);
+ Range range = ConvertOriginalToSkipped(it, offset, length);
float cssPxPerDevPx = aContext->
AppUnitsToFloatCSSPixels(aContext->AppUnitsPerDevPixel());
- gfxFloat advance = mTextRun->GetAdvanceWidth(offset, length, nullptr);
+ gfxFloat advance = mTextRun->GetAdvanceWidth(range, nullptr);
return aContext->AppUnitsToGfxUnits(advance) *
mLengthAdjustScaleFactor * cssPxPerDevPx;
}
@@ -4226,10 +4199,10 @@ SVGTextFrame::GetSubStringLength(nsIContent* aContent,
gfxSkipCharsIterator it =
run.mFrame->EnsureTextRun(nsTextFrame::eInflated);
gfxTextRun* textRun = run.mFrame->GetTextRun(nsTextFrame::eInflated);
- ConvertOriginalToSkipped(it, offset, length);
+ Range range = ConvertOriginalToSkipped(it, offset, length);
// Accumulate the advance.
- textLength += textRun->GetAdvanceWidth(offset, length, nullptr);
+ textLength += textRun->GetAdvanceWidth(range, nullptr);
}
run = it.Next();
@@ -4728,8 +4701,9 @@ SVGTextFrame::DetermineCharPositions(nsTArray& aPositions)
!it.IsOriginalCharSkipped() &&
(!textRun->IsLigatureGroupStart(it.GetSkippedOffset()) ||
!textRun->IsClusterStart(it.GetSkippedOffset()))) {
- nscoord advance = textRun->GetAdvanceWidth(it.GetSkippedOffset(), 1,
- nullptr);
+ uint32_t offset = it.GetSkippedOffset();
+ nscoord advance = textRun->
+ GetAdvanceWidth(Range(offset, offset + 1), nullptr);
(textRun->IsVertical() ? position.y : position.x) +=
textRun->IsRightToLeft() ? -advance : advance;
aPositions.AppendElement(lastPosition);
@@ -4743,9 +4717,8 @@ SVGTextFrame::DetermineCharPositions(nsTArray& aPositions)
textRun->IsLigatureGroupStart(it.GetSkippedOffset()) &&
textRun->IsClusterStart(it.GetSkippedOffset())) {
// A real visible character.
- uint32_t length = ClusterLength(textRun, it);
- nscoord advance = textRun->GetAdvanceWidth(it.GetSkippedOffset(),
- length, nullptr);
+ nscoord advance = textRun->
+ GetAdvanceWidth(ClusterRange(textRun, it), nullptr);
(textRun->IsVertical() ? position.y : position.x) +=
textRun->IsRightToLeft() ? -advance : advance;
lastPosition = position;
diff --git a/layout/svg/SVGTextFrame.h b/layout/svg/SVGTextFrame.h
index f94ea570a3..72a822af46 100644
--- a/layout/svg/SVGTextFrame.h
+++ b/layout/svg/SVGTextFrame.h
@@ -12,6 +12,7 @@
#include "gfxMatrix.h"
#include "gfxRect.h"
#include "gfxSVGGlyphs.h"
+#include "gfxTextRun.h"
#include "nsIContent.h" // for GetContent
#include "nsStubMutationObserver.h"
#include "nsSVGPaintServerFrame.h"
@@ -259,6 +260,7 @@ class SVGTextFrame final : public SVGTextFrameBase
friend class MutationObserver;
friend class nsDisplaySVGText;
+ typedef gfxTextRun::Range Range;
typedef mozilla::gfx::DrawTarget DrawTarget;
typedef mozilla::gfx::Path Path;
typedef mozilla::gfx::Point Point;
diff --git a/layout/xul/nsXULTooltipListener.cpp b/layout/xul/nsXULTooltipListener.cpp
index 613389e16d..8117ad3f44 100644
--- a/layout/xul/nsXULTooltipListener.cpp
+++ b/layout/xul/nsXULTooltipListener.cpp
@@ -358,7 +358,12 @@ nsXULTooltipListener::CheckTreeBodyMove(nsIDOMMouseEvent* aMouseEvent)
// determine if we are going to need a titletip
// XXX check the disabletitletips attribute on the tree content
mNeedTitletip = false;
- if (row >= 0 && obj.EqualsLiteral("text")) {
+ int16_t colType = -1;
+ if (col) {
+ col->GetType(&colType);
+ }
+ if (row >= 0 && obj.EqualsLiteral("text") &&
+ colType != nsITreeColumn::TYPE_PASSWORD) {
obx->IsCellCropped(row, col, &mNeedTitletip);
}
diff --git a/layout/xul/tree/nsITreeColumns.idl b/layout/xul/tree/nsITreeColumns.idl
index 9b27ce25e8..a601f3776b 100644
--- a/layout/xul/tree/nsITreeColumns.idl
+++ b/layout/xul/tree/nsITreeColumns.idl
@@ -32,6 +32,7 @@ interface nsITreeColumn : nsISupports
const short TYPE_TEXT = 1;
const short TYPE_CHECKBOX = 2;
const short TYPE_PROGRESSMETER = 3;
+ const short TYPE_PASSWORD = 4;
readonly attribute short type;
nsITreeColumn getNext();
diff --git a/layout/xul/tree/nsTreeBodyFrame.cpp b/layout/xul/tree/nsTreeBodyFrame.cpp
index 86ca9a5fa7..27a7a4a43d 100644
--- a/layout/xul/tree/nsTreeBodyFrame.cpp
+++ b/layout/xul/tree/nsTreeBodyFrame.cpp
@@ -66,6 +66,7 @@
#include "nsIScriptableRegion.h"
#include
#include "ScrollbarActivity.h"
+#include "../../editor/libeditor/nsTextEditRules.h"
#ifdef ACCESSIBILITY
#include "nsAccessibilityService.h"
@@ -3366,6 +3367,7 @@ nsTreeBodyFrame::PaintCell(int32_t aRowIndex,
if (dirtyRect.IntersectRect(aDirtyRect, elementRect)) {
switch (aColumn->GetType()) {
case nsITreeColumn::TYPE_TEXT:
+ case nsITreeColumn::TYPE_PASSWORD:
PaintText(aRowIndex, aColumn, elementRect, aPresContext, aRenderingContext, aDirtyRect, currX);
break;
case nsITreeColumn::TYPE_CHECKBOX:
@@ -3672,6 +3674,11 @@ nsTreeBodyFrame::PaintText(int32_t aRowIndex,
// Now obtain the text for our cell.
nsAutoString text;
mView->GetCellText(aRowIndex, aColumn, text);
+
+ if (aColumn->Type() == nsITreeColumn::TYPE_PASSWORD) {
+ nsTextEditRules::FillBufWithPWChars(&text, text.Length());
+ }
+
// We're going to paint this text so we need to ensure bidi is enabled if
// necessary
CheckTextForBidi(text);
diff --git a/layout/xul/tree/nsTreeColumns.cpp b/layout/xul/tree/nsTreeColumns.cpp
index 01dace53ab..18424bca4f 100644
--- a/layout/xul/tree/nsTreeColumns.cpp
+++ b/layout/xul/tree/nsTreeColumns.cpp
@@ -321,11 +321,13 @@ nsTreeColumn::Invalidate()
// Figure out our column type. Default type is text.
mType = nsITreeColumn::TYPE_TEXT;
static nsIContent::AttrValuesArray typestrings[] =
- {&nsGkAtoms::checkbox, &nsGkAtoms::progressmeter, nullptr};
+ {&nsGkAtoms::checkbox, &nsGkAtoms::progressmeter, &nsGkAtoms::password,
+ nullptr};
switch (mContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::type,
typestrings, eCaseMatters)) {
case 0: mType = nsITreeColumn::TYPE_CHECKBOX; break;
case 1: mType = nsITreeColumn::TYPE_PROGRESSMETER; break;
+ case 2: mType = nsITreeColumn::TYPE_PASSWORD; break;
}
// Fetch the crop style.
diff --git a/modules/libpref/Preferences.cpp b/modules/libpref/Preferences.cpp
index 55546fc3ee..e8bcbb8500 100644
--- a/modules/libpref/Preferences.cpp
+++ b/modules/libpref/Preferences.cpp
@@ -10,6 +10,7 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/HashFunctions.h"
+#include "mozilla/UniquePtrExtensions.h"
#include "nsXULAppAPI.h"
@@ -238,7 +239,6 @@ Preferences::SizeOfIncludingThisAndOtherStuff(mozilla::MallocSizeOf aMallocSizeO
}
}
if (gObserverTable) {
- n += aMallocSizeOf(gObserverTable);
n += gObserverTable->ShallowSizeOfIncludingThis(aMallocSizeOf);
for (auto iter = gObserverTable->Iter(); !iter.Done(); iter.Next()) {
n += iter.Key()->mPrefName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
@@ -942,25 +942,23 @@ Preferences::WritePrefFile(nsIFile* aFile)
if (NS_FAILED(rv))
return rv;
- nsAutoArrayPtr valueArray(new char*[gHashTable->EntryCount()]);
- memset(valueArray, 0, gHashTable->EntryCount() * sizeof(char*));
-
// get the lines that we're supposed to be writing to the file
- pref_savePrefs(gHashTable, valueArray);
+ UniquePtr valueArray = pref_savePrefs(gHashTable);
/* Sort the preferences to make a readable file on disk */
- NS_QuickSort(valueArray, gHashTable->EntryCount(), sizeof(char *),
+ NS_QuickSort(valueArray.get(), gHashTable->EntryCount(), sizeof(char *),
pref_CompareStrings, nullptr);
// write out the file header
outStream->Write(outHeader, sizeof(outHeader) - 1, &writeAmount);
- char** walker = valueArray;
- for (uint32_t valueIdx = 0; valueIdx < gHashTable->EntryCount(); valueIdx++, walker++) {
- if (*walker) {
- outStream->Write(*walker, strlen(*walker), &writeAmount);
+ for (uint32_t valueIdx = 0; valueIdx < gHashTable->EntryCount(); valueIdx++) {
+ char*& pref = valueArray[valueIdx];
+ if (pref) {
+ outStream->Write(pref, strlen(pref), &writeAmount);
outStream->Write(NS_LINEBREAK, NS_LINEBREAK_LEN, &writeAmount);
- NS_Free(*walker);
+ free(pref);
+ pref = nullptr;
}
}
@@ -995,7 +993,7 @@ static nsresult openPrefFile(nsIFile* aFile)
NS_ENSURE_TRUE(fileSize64 <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
uint32_t fileSize = (uint32_t)fileSize64;
- nsAutoArrayPtr fileBuffer(new char[fileSize]);
+ auto fileBuffer = MakeUniqueFallible(fileSize);
if (fileBuffer == nullptr)
return NS_ERROR_OUT_OF_MEMORY;
@@ -1008,10 +1006,10 @@ static nsresult openPrefFile(nsIFile* aFile)
uint32_t offset = 0;
for (;;) {
uint32_t amtRead = 0;
- rv = inStr->Read((char*)fileBuffer, fileSize, &amtRead);
+ rv = inStr->Read(fileBuffer.get(), fileSize, &amtRead);
if (NS_FAILED(rv) || amtRead == 0)
break;
- if (!PREF_ParseBuf(&ps, fileBuffer, amtRead))
+ if (!PREF_ParseBuf(&ps, fileBuffer.get(), amtRead))
rv2 = NS_ERROR_FILE_CORRUPTED;
offset += amtRead;
if (offset == fileSize) {
diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js
index 5ca5b20b48..6f8fa43c94 100644
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -127,22 +127,15 @@ pref("dom.indexedDB.logging.details", true);
// Enable profiler marks for indexedDB events.
pref("dom.indexedDB.logging.profiler-marks", false);
+// Whether or not File Handle is enabled.
+pref("dom.fileHandle.enabled", true);
+
// Whether or not selection events are enabled
pref("dom.select_events.enabled", true);
// Whether or not selection events on text controls are enabled
pref("dom.select_events.textcontrols.enabled", true);
-// Whether or not File Handle is enabled.
-pref("dom.fileHandle.enabled", true);
-
-// Whether or not the Permissions API is enabled.
-#ifdef NIGHTLY_BUILD
-pref("dom.permissions.enabled", true);
-#else
-pref("dom.permissions.enabled", false);
-#endif
-
// Whether or not Web Workers are enabled.
pref("dom.workers.enabled", true);
// The number of workers per domain allowed to run concurrently.
diff --git a/modules/libpref/prefapi.cpp b/modules/libpref/prefapi.cpp
index dd2776987e..1caa053861 100644
--- a/modules/libpref/prefapi.cpp
+++ b/modules/libpref/prefapi.cpp
@@ -318,9 +318,12 @@ pref_SetPref(const dom::PrefSetting& aPref)
return rv;
}
-void
-pref_savePrefs(PLDHashTable* aTable, char** aPrefArray)
+UniquePtr
+pref_savePrefs(PLDHashTable* aTable)
{
+ auto savedPrefs = MakeUnique(aTable->EntryCount());
+ memset(savedPrefs.get(), 0, aTable->EntryCount() * sizeof(char*));
+
int32_t j = 0;
for (auto iter = aTable->Iter(); !iter.Done(); iter.Next()) {
auto pref = static_cast(iter.Get());
@@ -360,12 +363,14 @@ pref_savePrefs(PLDHashTable* aTable, char** aPrefArray)
nsAutoCString prefName;
str_escape(pref->key, prefName);
- aPrefArray[j++] = ToNewCString(prefPrefix +
+ savedPrefs[j++] = ToNewCString(prefPrefix +
prefName +
NS_LITERAL_CSTRING("\", ") +
prefValue +
NS_LITERAL_CSTRING(");"));
}
+
+ return savedPrefs;
}
static void
diff --git a/modules/libpref/prefapi_private_data.h b/modules/libpref/prefapi_private_data.h
index 45b6a4d733..f91b0d6c74 100644
--- a/modules/libpref/prefapi_private_data.h
+++ b/modules/libpref/prefapi_private_data.h
@@ -9,6 +9,7 @@
#define prefapi_private_data_h
#include "mozilla/MemoryReporting.h"
+#include "mozilla/UniquePtr.h"
extern PLDHashTable* gHashTable;
extern bool gDirty;
@@ -19,8 +20,8 @@ class PrefSetting;
} // namespace dom
} // namespace mozilla
-void
-pref_savePrefs(PLDHashTable* aTable, char** aPrefArray);
+mozilla::UniquePtr
+pref_savePrefs(PLDHashTable* aTable);
nsresult
pref_SetPref(const mozilla::dom::PrefSetting& aPref);
diff --git a/netwerk/test/mochitests/mochitest.ini b/netwerk/test/mochitests/mochitest.ini
index 1bf9c4148b..b519769802 100644
--- a/netwerk/test/mochitests/mochitest.ini
+++ b/netwerk/test/mochitests/mochitest.ini
@@ -27,6 +27,7 @@ skip-if = e10s
[test_signed_web_packaged_app.html]
skip-if = e10s || buildapp != 'browser'
[test_web_packaged_app.html]
+skip-if = buildapp != 'mulet'
[test_signed_web_packaged_app_origin.html]
skip-if = e10s || buildapp != 'browser'
skip-if = buildapp == 'b2g' #no ssl support
diff --git a/testing/mochitest/tests/Harness_sanity/mochitest.ini b/testing/mochitest/tests/Harness_sanity/mochitest.ini
index 113a307eec..f3c2c5f24b 100644
--- a/testing/mochitest/tests/Harness_sanity/mochitest.ini
+++ b/testing/mochitest/tests/Harness_sanity/mochitest.ini
@@ -1,5 +1,5 @@
[DEFAULT]
-skip-if = buildapp == 'mulet' || buildapp == 'b2g'
+skip-if = buildapp == 'b2g'
[test_TestsRunningAfterSimpleTestFinish.html]
skip-if = true #depends on fix for bug 1048446
[test_add_task.html]
@@ -30,7 +30,7 @@ skip-if = toolkit == 'android' || e10s #No test app installed
[test_sanity_cleanup.html]
[test_sanity_cleanup2.html]
[test_sanityEventUtils.html]
-skip-if = toolkit == 'android' #bug 688052
+skip-if = buildapp == 'mulet' || toolkit == 'android' #bug 688052
[test_sanitySimpletest.html]
skip-if = toolkit == 'android' #bug 688052
[test_sanity_manifest.html]
diff --git a/testing/web-platform/mozilla/meta/MANIFEST.json b/testing/web-platform/mozilla/meta/MANIFEST.json
index 5aad985824..72557df142 100644
--- a/testing/web-platform/mozilla/meta/MANIFEST.json
+++ b/testing/web-platform/mozilla/meta/MANIFEST.json
@@ -505,12 +505,6 @@
"url": "/_mozilla/service-workers/service-worker/state.https.html"
}
],
- "service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html": [
- {
- "path": "service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html",
- "url": "/_mozilla/service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html"
- }
- ],
"service-workers/service-worker/synced-state.https.html": [
{
"path": "service-workers/service-worker/synced-state.https.html",
@@ -576,6 +570,12 @@
"path": "service-workers/service-worker/worker-interception.https.html",
"url": "/_mozilla/service-workers/service-worker/worker-interception.https.html"
}
+ ],
+ "service-workers/service-worker/xhr.https.html": [
+ {
+ "path": "service-workers/service-worker/xhr.https.html",
+ "url": "/_mozilla/service-workers/service-worker/xhr.https.html"
+ }
]
}
},
@@ -585,4 +585,4 @@
"rev": null,
"url_base": "/_mozilla/",
"version": 2
-}
\ No newline at end of file
+}
diff --git a/testing/web-platform/mozilla/meta/service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html.ini b/testing/web-platform/mozilla/meta/service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html.ini
deleted file mode 100644
index 3b7d472785..0000000000
--- a/testing/web-platform/mozilla/meta/service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[sync-xhr-doesnt-deadlock.https.html]
- type: testharness
- expected:
- if debug and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): CRASH
- if debug and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): CRASH
- if debug and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): CRASH
- [Verify SyncXHR does not deadlock]
- expected: FAIL
-
diff --git a/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock-iframe.html b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock-iframe.html
deleted file mode 100644
index 0fa7291162..0000000000
--- a/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock-iframe.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-Service Worker: SyncXHR doesn't deadlock iframe
-
diff --git a/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock.data b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock.data
deleted file mode 100644
index b6fc4c620b..0000000000
--- a/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock.data
+++ /dev/null
@@ -1 +0,0 @@
-hello
\ No newline at end of file
diff --git a/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock.js b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock.js
deleted file mode 100644
index 3e9093de5a..0000000000
--- a/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock.js
+++ /dev/null
@@ -1,5 +0,0 @@
-self.onfetch = function(event) {
- if (event.request.url.indexOf('sync-xhr-doesnt-deadlock.data') == -1)
- return;
- event.respondWith(fetch('404resource?bustcache=' + Date.now()));
-};
diff --git a/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/xhr.js b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/xhr.js
new file mode 100644
index 0000000000..387c4a48ed
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/xhr.js
@@ -0,0 +1,6 @@
+self.addEventListener('activate', function(event) {
+ event.waitUntil(clients.claim());
+ });
+self.addEventListener('message', function(event) {
+ event.data.port.postMessage({xhr: !!("XMLHttpRequest" in self)});
+ });
diff --git a/testing/web-platform/mozilla/tests/service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html b/testing/web-platform/mozilla/tests/service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html
deleted file mode 100644
index 357cf9d5a5..0000000000
--- a/testing/web-platform/mozilla/tests/service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html
+++ /dev/null
@@ -1,23 +0,0 @@
-
-Service Worker: SyncXHR doesn't deadlock
-
-
-
-
diff --git a/testing/web-platform/mozilla/tests/service-workers/service-worker/xhr.https.html b/testing/web-platform/mozilla/tests/service-workers/service-worker/xhr.https.html
new file mode 100644
index 0000000000..c03f1c955f
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/xhr.https.html
@@ -0,0 +1,34 @@
+
+Service Worker: XHR doesn't exist
+
+
+
+
+
diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json
index 32fb257e06..dcf1302802 100644
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -270,6 +270,13 @@
"kind": "boolean",
"description": "Was Fetch request initiated from the main thread?"
},
+ "FORCED_DEVICE_RESET_REASON": {
+ "expires_in_version": "never",
+ "kind": "enumerated",
+ "n_values": 50,
+ "releaseChannelCollection": "opt-out",
+ "description": "GPU Forced Device Reset Reason (OpenSharedHandle)"
+ },
"FORGET_SKIPPABLE_MAX": {
"expires_in_version": "never",
"kind": "exponential",
diff --git a/toolkit/content/widgets/tree.xml b/toolkit/content/widgets/tree.xml
index 11a5695ec0..448b7f60b8 100644
--- a/toolkit/content/widgets/tree.xml
+++ b/toolkit/content/widgets/tree.xml
@@ -341,8 +341,10 @@
return false;
if (row < 0 || row >= this.view.rowCount || !column)
return false;
- if (column.type != Components.interfaces.nsITreeColumn.TYPE_TEXT ||
- column.cycler || !this.view.isEditable(row, column))
+ if (column.type != Components.interfaces.nsITreeColumn.TYPE_TEXT &&
+ column.type != Components.interfaces.nsITreeColumn.TYPE_PASSWORD)
+ return false;
+ if (column.cycler || !this.view.isEditable(row, column))
return false;
// Beyond this point, we are going to edit the cell.
diff --git a/toolkit/devtools/apps/tests/mochitest.ini b/toolkit/devtools/apps/tests/mochitest.ini
index d640516174..b7ab3bef86 100644
--- a/toolkit/devtools/apps/tests/mochitest.ini
+++ b/toolkit/devtools/apps/tests/mochitest.ini
@@ -1,9 +1,8 @@
[DEFAULT]
skip-if = e10s
+skip-if = (buildapp != 'b2g' && buildapp != 'mulet')
support-files =
debugger-protocol-helper.js
redirect.sjs
[test_webapps_actor.html]
-# The mochitest doesn't work on fennec yet
-skip-if = toolkit == 'android'
diff --git a/uriloader/prefetch/nsOfflineCacheUpdateService.cpp b/uriloader/prefetch/nsOfflineCacheUpdateService.cpp
index c053d29f08..5718e86ab8 100644
--- a/uriloader/prefetch/nsOfflineCacheUpdateService.cpp
+++ b/uriloader/prefetch/nsOfflineCacheUpdateService.cpp
@@ -53,6 +53,7 @@ using namespace mozilla;
using namespace mozilla::dom;
static nsOfflineCacheUpdateService *gOfflineCacheUpdateService = nullptr;
+static bool sAllowOfflineCache = true;
nsTHashtable* nsOfflineCacheUpdateService::mAllowedDomains = nullptr;
@@ -246,6 +247,10 @@ nsOfflineCacheUpdateService::nsOfflineCacheUpdateService()
, mUpdateRunning(false)
, mLowFreeSpace(false)
{
+ MOZ_ASSERT(NS_IsMainThread());
+ Preferences::AddBoolVarCache(&sAllowOfflineCache,
+ "browser.cache.offline.enable",
+ true);
}
nsOfflineCacheUpdateService::~nsOfflineCacheUpdateService()
@@ -604,6 +609,10 @@ OfflineAppPermForPrincipal(nsIPrincipal *aPrincipal,
{
*aAllowed = false;
+ if (!sAllowOfflineCache) {
+ return NS_OK;
+ }
+
if (!aPrincipal)
return NS_ERROR_INVALID_ARG;
@@ -696,6 +705,10 @@ nsOfflineCacheUpdateService::AllowOfflineApp(nsIDOMWindow *aWindow,
{
nsresult rv;
+ if (!sAllowOfflineCache) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
if (GeckoProcessType_Default != XRE_GetProcessType()) {
ContentChild* child = ContentChild::GetSingleton();
diff --git a/xpcom/ds/StickyTimeDuration.h b/xpcom/ds/StickyTimeDuration.h
index 750e813ea8..39a887dbce 100644
--- a/xpcom/ds/StickyTimeDuration.h
+++ b/xpcom/ds/StickyTimeDuration.h
@@ -159,7 +159,7 @@ StickyTimeDurationValueCalculator::Multiply(int64_t aA,
// return -Forever if the signs differ, or +Forever otherwise.
if (aA == INT64_MAX || aA == INT64_MIN ||
aB == INT64_MAX || aB == INT64_MIN) {
- return (aA >= 0) ^ (aB >= 0) ? INT64_MAX : INT64_MIN;
+ return (aA >= 0) ^ (aB >= 0) ? INT64_MIN : INT64_MAX;
}
return aA * aB;
@@ -177,7 +177,7 @@ StickyTimeDurationValueCalculator::Multiply(int64_t aA, double aB)
// +/-Forever or +/-Infinity, then return -Forever if the signs differ,
// or +Forever otherwise.
if (aA == INT64_MAX || aA == INT64_MIN || IsInfinite(aB)) {
- return (aA >= 0) ^ (aB >= 0.0) ? INT64_MAX : INT64_MIN;
+ return (aA >= 0) ^ (aB >= 0.0) ? INT64_MIN : INT64_MAX;
}
return aA * aB;
diff --git a/xpcom/ds/nsHashPropertyBag.cpp b/xpcom/ds/nsHashPropertyBag.cpp
index 32575487f6..6f9fc8dec3 100644
--- a/xpcom/ds/nsHashPropertyBag.cpp
+++ b/xpcom/ds/nsHashPropertyBag.cpp
@@ -160,7 +160,7 @@ IMPL_GETSETPROPERTY_AS(Bool, bool)
NS_IMETHODIMP
nsHashPropertyBagBase::GetPropertyAsAString(const nsAString& aProp,
- nsAString& aResult)
+ nsAString& aResult)
{
nsIVariant* v = mPropertyHash.GetWeak(aProp);
if (!v) {
@@ -171,7 +171,7 @@ nsHashPropertyBagBase::GetPropertyAsAString(const nsAString& aProp,
NS_IMETHODIMP
nsHashPropertyBagBase::GetPropertyAsACString(const nsAString& aProp,
- nsACString& aResult)
+ nsACString& aResult)
{
nsIVariant* v = mPropertyHash.GetWeak(aProp);
if (!v) {
@@ -182,7 +182,7 @@ nsHashPropertyBagBase::GetPropertyAsACString(const nsAString& aProp,
NS_IMETHODIMP
nsHashPropertyBagBase::GetPropertyAsAUTF8String(const nsAString& aProp,
- nsACString& aResult)
+ nsACString& aResult)
{
nsIVariant* v = mPropertyHash.GetWeak(aProp);
if (!v) {
@@ -193,8 +193,8 @@ nsHashPropertyBagBase::GetPropertyAsAUTF8String(const nsAString& aProp,
NS_IMETHODIMP
nsHashPropertyBagBase::GetPropertyAsInterface(const nsAString& aProp,
- const nsIID& aIID,
- void** aResult)
+ const nsIID& aIID,
+ void** aResult)
{
nsIVariant* v = mPropertyHash.GetWeak(aProp);
if (!v) {
@@ -215,7 +215,7 @@ nsHashPropertyBagBase::GetPropertyAsInterface(const nsAString& aProp,
NS_IMETHODIMP
nsHashPropertyBagBase::SetPropertyAsAString(const nsAString& aProp,
- const nsAString& aValue)
+ const nsAString& aValue)
{
nsCOMPtr var = new nsVariant();
var->SetAsAString(aValue);
@@ -224,7 +224,7 @@ nsHashPropertyBagBase::SetPropertyAsAString(const nsAString& aProp,
NS_IMETHODIMP
nsHashPropertyBagBase::SetPropertyAsACString(const nsAString& aProp,
- const nsACString& aValue)
+ const nsACString& aValue)
{
nsCOMPtr var = new nsVariant();
var->SetAsACString(aValue);
@@ -233,7 +233,7 @@ nsHashPropertyBagBase::SetPropertyAsACString(const nsAString& aProp,
NS_IMETHODIMP
nsHashPropertyBagBase::SetPropertyAsAUTF8String(const nsAString& aProp,
- const nsACString& aValue)
+ const nsACString& aValue)
{
nsCOMPtr var = new nsVariant();
var->SetAsAUTF8String(aValue);
@@ -242,7 +242,7 @@ nsHashPropertyBagBase::SetPropertyAsAUTF8String(const nsAString& aProp,
NS_IMETHODIMP
nsHashPropertyBagBase::SetPropertyAsInterface(const nsAString& aProp,
- nsISupports* aValue)
+ nsISupports* aValue)
{
nsCOMPtr var = new nsVariant();
var->SetAsISupports(aValue);
diff --git a/xpcom/ds/nsObserverService.cpp b/xpcom/ds/nsObserverService.cpp
index 0db4b59326..1c99fabaad 100644
--- a/xpcom/ds/nsObserverService.cpp
+++ b/xpcom/ds/nsObserverService.cpp
@@ -49,9 +49,9 @@ nsObserverService::CollectReports(nsIHandleReportCallback* aHandleReport,
size_t mReferentCount;
};
- size_t numStrong = 0;
- size_t numWeakAlive = 0;
- size_t numWeakDead = 0;
+ size_t totalNumStrong = 0;
+ size_t totalNumWeakAlive = 0;
+ size_t totalNumWeakDead = 0;
nsTArray suspectObservers;
for (auto iter = mObserverTopicTable.Iter(); !iter.Done(); iter.Next()) {
@@ -60,26 +60,34 @@ nsObserverService::CollectReports(nsIHandleReportCallback* aHandleReport,
continue;
}
+ size_t topicNumStrong = 0;
+ size_t topicNumWeakAlive = 0;
+ size_t topicNumWeakDead = 0;
+
nsTArray& observers = observerList->mObservers;
for (uint32_t i = 0; i < observers.Length(); i++) {
if (observers[i].isWeakRef) {
nsCOMPtr observerRef(
do_QueryReferent(observers[i].asWeak()));
if (observerRef) {
- numWeakAlive++;
+ topicNumWeakAlive++;
} else {
- numWeakDead++;
+ topicNumWeakDead++;
}
} else {
- numStrong++;
+ topicNumStrong++;
}
}
+ totalNumStrong += topicNumStrong;
+ totalNumWeakAlive += topicNumWeakAlive;
+ totalNumWeakDead += topicNumWeakDead;
+
// Keep track of topics that have a suspiciously large number
// of referents (symptom of leaks).
- size_t total = numStrong + numWeakAlive + numWeakDead;
- if (total > kSuspectReferentCount) {
- SuspectObserver suspect(observerList->GetKey(), total);
+ size_t topicTotal = topicNumStrong + topicNumWeakAlive + topicNumWeakDead;
+ if (topicTotal > kSuspectReferentCount) {
+ SuspectObserver suspect(observerList->GetKey(), topicTotal);
suspectObservers.AppendElement(suspect);
}
}
@@ -107,7 +115,7 @@ nsObserverService::CollectReports(nsIHandleReportCallback* aHandleReport,
rv = aHandleReport->Callback(
/* process */ EmptyCString(),
NS_LITERAL_CSTRING("observer-service/referent/strong"),
- KIND_OTHER, UNITS_COUNT, numStrong,
+ KIND_OTHER, UNITS_COUNT, totalNumStrong,
NS_LITERAL_CSTRING("The number of strong references held by the "
"observer service."),
aData);
@@ -119,7 +127,7 @@ nsObserverService::CollectReports(nsIHandleReportCallback* aHandleReport,
rv = aHandleReport->Callback(
/* process */ EmptyCString(),
NS_LITERAL_CSTRING("observer-service/referent/weak/alive"),
- KIND_OTHER, UNITS_COUNT, numWeakAlive,
+ KIND_OTHER, UNITS_COUNT, totalNumWeakAlive,
NS_LITERAL_CSTRING("The number of weak references held by the "
"observer service that are still alive."),
aData);
@@ -131,7 +139,7 @@ nsObserverService::CollectReports(nsIHandleReportCallback* aHandleReport,
rv = aHandleReport->Callback(
/* process */ EmptyCString(),
NS_LITERAL_CSTRING("observer-service/referent/weak/dead"),
- KIND_OTHER, UNITS_COUNT, numWeakDead,
+ KIND_OTHER, UNITS_COUNT, totalNumWeakDead,
NS_LITERAL_CSTRING("The number of weak references held by the "
"observer service that are dead."),
aData);
diff --git a/xpcom/ds/nsPersistentProperties.cpp b/xpcom/ds/nsPersistentProperties.cpp
index 67bdb473a0..69fef91097 100644
--- a/xpcom/ds/nsPersistentProperties.cpp
+++ b/xpcom/ds/nsPersistentProperties.cpp
@@ -523,11 +523,11 @@ nsPersistentProperties::SetStringProperty(const nsACString& aKey,
{
const nsAFlatCString& flatKey = PromiseFlatCString(aKey);
auto entry = static_cast
- (mTable.Add(flatKey.get(), mozilla::fallible));
+ (mTable.Add(flatKey.get()));
if (entry->mKey) {
aOldValue = entry->mValue;
- NS_WARNING(nsPrintfCString("the property %s already exists\n",
+ NS_WARNING(nsPrintfCString("the property %s already exists",
flatKey.get()).get());
} else {
aOldValue.Truncate();
diff --git a/xpcom/ds/nsSupportsArray.cpp b/xpcom/ds/nsSupportsArray.cpp
index 0d1696e227..f20dd614e9 100644
--- a/xpcom/ds/nsSupportsArray.cpp
+++ b/xpcom/ds/nsSupportsArray.cpp
@@ -189,6 +189,9 @@ nsSupportsArray::Read(nsIObjectInputStream* aStream)
uint32_t newArraySize;
rv = aStream->Read32(&newArraySize);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
if (newArraySize <= kAutoArraySize) {
if (mArray != mAutoArray) {
diff --git a/xpcom/ds/nsWindowsRegKey.cpp b/xpcom/ds/nsWindowsRegKey.cpp
index c9e68b7c0a..f75b51b8cc 100644
--- a/xpcom/ds/nsWindowsRegKey.cpp
+++ b/xpcom/ds/nsWindowsRegKey.cpp
@@ -310,7 +310,7 @@ nsWindowsRegKey::ReadStringValue(const nsAString& aName, nsAString& aResult)
// This must be a string type in order to fetch the value as a string.
// We're being a bit forgiving here by allowing types other than REG_SZ.
- if (type != REG_SZ && type == REG_EXPAND_SZ && type == REG_MULTI_SZ) {
+ if (type != REG_SZ && type != REG_EXPAND_SZ && type != REG_MULTI_SZ) {
return NS_ERROR_FAILURE;
}
diff --git a/xpcom/tests/unit/test_windows_registry.js b/xpcom/tests/unit/test_windows_registry.js
new file mode 100644
index 0000000000..9a17678f83
--- /dev/null
+++ b/xpcom/tests/unit/test_windows_registry.js
@@ -0,0 +1,205 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et: */
+
+/* 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/. */
+
+const Cr = Components.results;
+const Ci = Components.interfaces;
+const Cc = Components.classes;
+const Cu = Components.utils;
+const CC = Components.Constructor;
+
+const nsIWindowsRegKey = Ci.nsIWindowsRegKey;
+let regKeyComponent = Cc["@mozilla.org/windows-registry-key;1"];
+
+function run_test()
+{
+ //* create a key structure in a spot that's normally writable (somewhere under HKCU).
+ let testKey = regKeyComponent.createInstance(nsIWindowsRegKey);
+
+ // If it's already present because a previous test crashed or didn't clean up properly, clean it up first.
+ let keyName = BASE_PATH + "\\" + TESTDATA_KEYNAME;
+ setup_test_run(testKey, keyName);
+
+ //* test that the write* functions write stuff
+ test_writing_functions(testKey);
+
+ //* check that the valueCount/getValueName functions work for the values we just wrote
+ test_value_functions(testKey);
+
+ //* check that the get* functions work for the values we just wrote.
+ test_reading_functions(testKey);
+
+ //* check that the get* functions fail with the right exception codes if we ask for the wrong type or if the value name doesn't exist at all
+ test_invalidread_functions(testKey);
+
+ //* check that creating/enumerating/deleting child keys works
+ test_childkey_functions(testKey);
+
+ test_watching_functions(testKey);
+
+ //* clean up
+ cleanup_test_run(testKey, keyName);
+}
+
+function setup_test_run(testKey, keyName)
+{
+ do_print("Setup test run");
+ try {
+ testKey.open(nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, keyName, nsIWindowsRegKey.ACCESS_READ);
+ do_print("Test key exists. Needs cleanup.");
+ cleanup_test_run(testKey, keyName);
+ }
+ catch (e if (e instanceof Ci.nsIException && e.result == Cr.NS_ERROR_FAILURE))
+ {
+ }
+
+ testKey.create(nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, keyName, nsIWindowsRegKey.ACCESS_ALL);
+}
+
+function test_writing_functions(testKey)
+{
+ strictEqual(testKey.valueCount, 0);
+
+ strictEqual(testKey.hasValue(TESTDATA_STRNAME), false);
+ testKey.writeStringValue(TESTDATA_STRNAME, TESTDATA_STRVALUE);
+ strictEqual(testKey.hasValue(TESTDATA_STRNAME), true);
+
+ strictEqual(testKey.hasValue(TESTDATA_INTNAME), false);
+ testKey.writeIntValue(TESTDATA_INTNAME, TESTDATA_INTVALUE);
+
+ strictEqual(testKey.hasValue(TESTDATA_INT64NAME), false);
+ testKey.writeInt64Value(TESTDATA_INT64NAME, TESTDATA_INT64VALUE);
+
+ strictEqual(testKey.hasValue(TESTDATA_BINARYNAME), false);
+ testKey.writeBinaryValue(TESTDATA_BINARYNAME, TESTDATA_BINARYVALUE);
+}
+
+function test_value_functions(testKey)
+{
+ strictEqual(testKey.valueCount, 4);
+ strictEqual(testKey.getValueName(0), TESTDATA_STRNAME);
+ strictEqual(testKey.getValueName(1), TESTDATA_INTNAME);
+ strictEqual(testKey.getValueName(2), TESTDATA_INT64NAME);
+ strictEqual(testKey.getValueName(3), TESTDATA_BINARYNAME);
+}
+
+function test_reading_functions(testKey)
+{
+ strictEqual(testKey.getValueType(TESTDATA_STRNAME), nsIWindowsRegKey.TYPE_STRING);
+ strictEqual(testKey.readStringValue(TESTDATA_STRNAME), TESTDATA_STRVALUE);
+
+ strictEqual(testKey.getValueType(TESTDATA_INTNAME), nsIWindowsRegKey.TYPE_INT);
+ strictEqual(testKey.readIntValue(TESTDATA_INTNAME), TESTDATA_INTVALUE);
+
+ strictEqual(testKey.getValueType(TESTDATA_INT64NAME), nsIWindowsRegKey.TYPE_INT64);
+ strictEqual( testKey.readInt64Value(TESTDATA_INT64NAME), TESTDATA_INT64VALUE);
+
+ strictEqual(testKey.getValueType(TESTDATA_BINARYNAME), nsIWindowsRegKey.TYPE_BINARY);
+ strictEqual( testKey.readBinaryValue(TESTDATA_BINARYNAME), TESTDATA_BINARYVALUE);
+}
+
+function test_invalidread_functions(testKey)
+{
+ try {
+ testKey.readIntValue(TESTDATA_STRNAME);
+ do_throw("Reading an integer from a string registry value should throw.");
+ } catch (e if (e instanceof Ci.nsIException && e.result == Cr.NS_ERROR_FAILURE)) {
+ }
+
+ try {
+ let val = testKey.readStringValue(TESTDATA_INTNAME);
+ do_throw("Reading an string from an Int registry value should throw." + val);
+ } catch (e if (e instanceof Ci.nsIException && e.result == Cr.NS_ERROR_FAILURE)) {
+ }
+
+ try {
+ testKey.readStringValue(TESTDATA_INT64NAME);
+ do_throw("Reading an string from an Int64 registry value should throw.");
+ } catch (e if (e instanceof Ci.nsIException && e.result == Cr.NS_ERROR_FAILURE)) {
+ }
+
+ try {
+ testKey.readStringValue(TESTDATA_BINARYNAME);
+ do_throw("Reading a string from an Binary registry value should throw.");
+ } catch (e if (e instanceof Ci.nsIException && e.result == Cr.NS_ERROR_FAILURE)) {
+ }
+
+}
+
+function test_childkey_functions(testKey)
+{
+ strictEqual(testKey.childCount, 0);
+ strictEqual(testKey.hasChild(TESTDATA_CHILD_KEY), false);
+
+ let childKey = testKey.createChild(TESTDATA_CHILD_KEY, nsIWindowsRegKey.ACCESS_ALL);
+ childKey.close();
+
+ strictEqual(testKey.childCount, 1);
+ strictEqual(testKey.hasChild(TESTDATA_CHILD_KEY), true);
+ strictEqual(testKey.getChildName(0), TESTDATA_CHILD_KEY);
+
+ childKey = testKey.openChild(TESTDATA_CHILD_KEY, nsIWindowsRegKey.ACCESS_ALL);
+ testKey.removeChild(TESTDATA_CHILD_KEY);
+ strictEqual(testKey.childCount, 0);
+ strictEqual(testKey.hasChild(TESTDATA_CHILD_KEY), false);
+}
+
+function test_watching_functions(testKey)
+{
+ strictEqual(testKey.isWatching(), false);
+ strictEqual(testKey.hasChanged(), false);
+
+ testKey.startWatching(true);
+ strictEqual(testKey.isWatching(), true);
+
+ testKey.stopWatching();
+ strictEqual(testKey.isWatching(), false);
+
+ // Create a child key, and update a value
+ let childKey = testKey.createChild(TESTDATA_CHILD_KEY, nsIWindowsRegKey.ACCESS_ALL);
+ childKey.writeIntValue(TESTDATA_INTNAME, TESTDATA_INTVALUE);
+
+ // Start a recursive watch, and update the child's value
+ testKey.startWatching(true);
+ strictEqual(testKey.isWatching(), true);
+
+ childKey.writeIntValue(TESTDATA_INTNAME, 0);
+ strictEqual(testKey.hasChanged(), true);
+ testKey.stopWatching();
+ strictEqual(testKey.isWatching(), false);
+
+ childKey.removeValue(TESTDATA_INTNAME);
+ childKey.close();
+ testKey.removeChild(TESTDATA_CHILD_KEY);
+}
+
+function cleanup_test_run(testKey, keyName)
+{
+ do_print("Cleaning up test.");
+
+ for (var i = 0; i < testKey.childCount; i++) {
+ testKey.removeChild(testKey.getChildName(i));
+ }
+ testKey.close();
+
+ let baseKey = regKeyComponent.createInstance(nsIWindowsRegKey);
+ baseKey.open(nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, BASE_PATH, nsIWindowsRegKey.ACCESS_ALL);
+ baseKey.removeChild(TESTDATA_KEYNAME);
+ baseKey.close();
+}
+
+// Test data used above.
+const BASE_PATH = "SOFTWARE";
+const TESTDATA_KEYNAME = "TestRegXPC";
+const TESTDATA_STRNAME = "AString";
+const TESTDATA_STRVALUE = "The quick brown fox jumps over the lazy dog.";
+const TESTDATA_INTNAME = "AnInteger";
+const TESTDATA_INTVALUE = 65536;
+const TESTDATA_INT64NAME = "AnInt64";
+const TESTDATA_INT64VALUE = 9223372036854775807;
+const TESTDATA_BINARYNAME = "ABinary";
+const TESTDATA_BINARYVALUE = "She sells seashells by the seashore";
+const TESTDATA_CHILD_KEY = "TestChildKey";
diff --git a/xpcom/tests/unit/xpcshell.ini b/xpcom/tests/unit/xpcshell.ini
index 371b8a846a..6b75a1b710 100644
--- a/xpcom/tests/unit/xpcshell.ini
+++ b/xpcom/tests/unit/xpcshell.ini
@@ -77,3 +77,5 @@ skip-if = os == "win"
fail-if = os == "android"
[test_file_renameTo.js]
[test_notxpcom_scriptable.js]
+[test_windows_registry.js]
+skip-if = os != "win"