import change from rmottola/Arctic-Fox:

- Bug 1135100 - Don't update GC thing pointers that haven't changed after marking r=terrence (0df3ea820)
- Bug 1135857 - Remove ContentClientIncremental. r=mattwoodrow (059587352)
- Bug 1135809 - add apz. prefs to about:support. r=kats (6439aaf6b)
- Bug 1135361 - Fix position of ruby annotation in vertical-rl mode when justification is applied to the base. r=jfkthame (a00bb53be)
- Bug 1133288 - Remove nonstandard expression closures from editor. r=ehsan (605992184)
- Bug 1135361 - Reftest for ruby positioning in justified vertical text. r=xidorn (60fe87ae3)
- Bug 1135984 - Fix typo which made Context.__init__ set the unused exe (312c35ef2)
- Bug 1077864, Part 1: Check consistency of certificates' signature and signatureAlgorithm fields, r=keeler (9a11f90c3)
- Bug 1077864, Part 2: Override the trust level for OCSP response signer certs so that they are never considered trust anchors, r=keeler (c46772e6d)
- Bug 1077864, Part 3: update nsserrors.properties so error message gets localized. (935233549)
- Bug 1135407: Factor out duplicate logic in tests, r=keeler (383ff80c5)
- Bug 1131767: Prune away paths using unacceptable algorithms earlier, r=keeler (55182b7e2)
- Followup to Bug 1135563 - uiUnsupportedAlreadyNotified.js doesn't use httpd.js. r=me (cef9dbdcd)
- Bug 1135563 - Fix several javascript warnings for xpcshell app update tests and cleanup style. r=spohl (6330eb78c)
- Bug 1123019 - In DrawTargetTiled::StrokeRect and StrokeLine, skip tiles that don't intersect the stroke. r=jrmuizel (71afc7653)
- Bug 1123019 - Shrink clipped stroked rectangles and stroked lines. r=jrmuizel (17e93d70f)
- Bug 1123019 - Actually use the clipped rect variable. r=jrmuizel (29c96ab43)
This commit is contained in:
2019-09-04 21:12:58 +08:00
parent eb1f745f35
commit f672f60d2d
73 changed files with 1383 additions and 2036 deletions
+7 -7
View File
@@ -19,8 +19,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=519928
var iframe = document.getElementById("load-frame");
function enableJS() allowJS(true, iframe);
function disableJS() allowJS(false, iframe);
function enableJS() { allowJS(true, iframe); }
function disableJS() { allowJS(false, iframe); }
function allowJS(allow, frame) {
SpecialPowers.wrap(frame.contentWindow)
.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
@@ -28,6 +28,7 @@ function allowJS(allow, frame) {
.QueryInterface(SpecialPowers.Ci.nsIDocShell)
.allowJavascript = allow;
}
function expectJSAllowed(allowed, testCondition, callback) {
window.ICanRunMyJS = false;
var self_ = window;
@@ -49,8 +50,8 @@ function expectJSAllowed(allowed, testCondition, callback) {
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
var enterDesignMode = function() document.designMode = "on";
var leaveDesignMode = function() document.designMode = "off";
var enterDesignMode = function() { document.designMode = "on"; };
var leaveDesignMode = function() { document.designMode = "off"; };
expectJSAllowed(false, disableJS, function() {
expectJSAllowed(true, enableJS, function() {
expectJSAllowed(true, enterDesignMode, function() {
@@ -59,8 +60,8 @@ addLoadEvent(function() {
expectJSAllowed(false, enterDesignMode, function() {
expectJSAllowed(false, leaveDesignMode, function() {
expectJSAllowed(true, enableJS, function() {
enterDesignMode = function() iframe.contentDocument.designMode = "on";
leaveDesignMode = function() iframe.contentDocument.designMode = "off";
enterDesignMode = function() { iframe.contentDocument.designMode = "on"; };
leaveDesignMode = function() { iframe.contentDocument.designMode = "off"; };
expectJSAllowed(false, disableJS, function() {
expectJSAllowed(true, enableJS, function() {
expectJSAllowed(true, enterDesignMode, function() {
@@ -120,4 +121,3 @@ function testDocumentDisabledJS() {
</pre>
</body>
</html>
@@ -45,7 +45,7 @@ function copyCF_HTML(cfhtml, success, failure) {
var flavors = [CF_HTML];
if (!cb.hasDataMatchingFlavors(flavors, flavors.length, cb.kGlobalClipboard)) {
setTimeout(function() copyCF_HTML_worker(success, failure), 100);
setTimeout(function() { copyCF_HTML_worker(success, failure); }, 100);
return;
}
@@ -59,7 +59,7 @@ function copyCF_HTML(cfhtml, success, failure) {
trans.getTransferData(CF_HTML, data, {});
data = SpecialPowers.wrap(data).value.QueryInterface(Ci.nsISupportsCString).data;
} catch (e) {
setTimeout(function() copyCF_HTML_worker(success, failure), 100);
setTimeout(function() { copyCF_HTML_worker(success, failure); }, 100);
return;
}
success();
+108 -108
View File
@@ -119,175 +119,175 @@ var tests = [
isIFrame: true,
payload: dataPayload,
iframeCount: 0,
rootElement: function() document.getElementById("a").contentDocument.documentElement
rootElement() { return document.getElementById("a").contentDocument.documentElement; },
},
{
id: "b",
isIFrame: true,
payload: jsPayload,
iframeCount: 0,
rootElement: function() document.getElementById("b").contentDocument.documentElement
rootElement() { return document.getElementById("b").contentDocument.documentElement; },
},
{
id: "c",
isIFrame: true,
payload: httpPayload,
iframeCount: 0,
rootElement: function() document.getElementById("c").contentDocument.documentElement
rootElement() { return document.getElementById("c").contentDocument.documentElement; },
},
{
id: "g",
isIFrame: true,
payload: scriptPayload,
rootElement: function() document.getElementById("g").contentDocument.documentElement,
rootElement() { return document.getElementById("g").contentDocument.documentElement; },
iframeCount: 0
},
{
id: "h",
isIFrame: true,
payload: scriptExternalPayload,
rootElement: function() document.getElementById("h").contentDocument.documentElement,
rootElement() { return document.getElementById("h").contentDocument.documentElement; },
iframeCount: 0
},
{
id: "d",
payload: dataPayload,
iframeCount: 0,
rootElement: function() document.getElementById("d")
rootElement() { return document.getElementById("d"); },
},
{
id: "e",
payload: jsPayload,
iframeCount: 0,
rootElement: function() document.getElementById("e")
rootElement() { return document.getElementById("e"); },
},
{
id: "f",
payload: httpPayload,
iframeCount: 0,
rootElement: function() document.getElementById("f")
rootElement() { return document.getElementById("f"); },
},
{
id: "i",
payload: scriptPayload,
rootElement: function() document.getElementById("i"),
rootElement() { return document.getElementById("i"); },
iframeCount: 0
},
{
id: "j",
payload: scriptExternalPayload,
rootElement: function() document.getElementById("j"),
rootElement() { return document.getElementById("j"); },
iframeCount: 0
},
{
id: "k",
isIFrame: true,
payload: validStyle1Payload,
rootElement: function() document.getElementById("k").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("style"), -1, "Should have retained style")
rootElement() { return document.getElementById("k").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("style"), -1, "Should have retained style"); },
},
{
id: "l",
payload: validStyle1Payload,
rootElement: function() document.getElementById("l"),
checkResult: function(html) isnot(html.indexOf("style"), -1, "Should have retained style")
rootElement() { return document.getElementById("l"); },
checkResult(html) { isnot(html.indexOf("style"), -1, "Should have retained style"); },
},
{
id: "m",
isIFrame: true,
payload: validStyle2Payload,
rootElement: function() document.getElementById("m").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("style"), -1, "Should have retained style")
rootElement() { return document.getElementById("m").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("style"), -1, "Should have retained style"); },
},
{
id: "n",
payload: validStyle2Payload,
rootElement: function() document.getElementById("n"),
checkResult: function(html) isnot(html.indexOf("style"), -1, "Should have retained style")
rootElement() { return document.getElementById("n"); },
checkResult(html) { isnot(html.indexOf("style"), -1, "Should have retained style"); },
},
{
id: "o",
isIFrame: true,
payload: invalidStyle1Payload,
rootElement: function() document.getElementById("o").contentDocument.documentElement,
checkResult: function(html) is(html.indexOf("binding"), -1, "Should not have retained the binding style")
rootElement() { return document.getElementById("o").contentDocument.documentElement; },
checkResult(html) { is(html.indexOf("binding"), -1, "Should not have retained the binding style"); },
},
{
id: "p",
payload: invalidStyle1Payload,
rootElement: function() document.getElementById("p"),
checkResult: function(html) is(html.indexOf("binding"), -1, "Should not have retained the binding style")
rootElement() { return document.getElementById("p"); },
checkResult(html) { is(html.indexOf("binding"), -1, "Should not have retained the binding style"); },
},
{
id: "q",
isIFrame: true,
payload: invalidStyle2Payload,
rootElement: function() document.getElementById("q").contentDocument.documentElement,
checkResult: function(html) is(html.indexOf("binding"), -1, "Should not have retained the binding style")
rootElement() { return document.getElementById("q").contentDocument.documentElement; },
checkResult(html) { is(html.indexOf("binding"), -1, "Should not have retained the binding style"); },
},
{
id: "r",
payload: invalidStyle2Payload,
rootElement: function() document.getElementById("r"),
checkResult: function(html) is(html.indexOf("binding"), -1, "Should not have retained the binding style")
rootElement() { return document.getElementById("r"); },
checkResult(html) { is(html.indexOf("binding"), -1, "Should not have retained the binding style"); },
},
{
id: "s",
isIFrame: true,
payload: invalidStyle1Payload,
rootElement: function() document.getElementById("s").contentDocument.documentElement,
checkResult: function(html) is(html.indexOf("xxx"), -1, "Should not have retained the import style")
rootElement() { return document.getElementById("s").contentDocument.documentElement; },
checkResult(html) { is(html.indexOf("xxx"), -1, "Should not have retained the import style"); },
},
{
id: "t",
payload: invalidStyle1Payload,
rootElement: function() document.getElementById("t"),
checkResult: function(html) is(html.indexOf("xxx"), -1, "Should not have retained the import style")
rootElement() { return document.getElementById("t"); },
checkResult(html) { is(html.indexOf("xxx"), -1, "Should not have retained the import style"); },
},
{
id: "u",
isIFrame: true,
payload: invalidStyle2Payload,
rootElement: function() document.getElementById("u").contentDocument.documentElement,
checkResult: function(html) is(html.indexOf("xxx"), -1, "Should not have retained the import style")
rootElement() { return document.getElementById("u").contentDocument.documentElement; },
checkResult(html) { is(html.indexOf("xxx"), -1, "Should not have retained the import style"); },
},
{
id: "v",
payload: invalidStyle2Payload,
rootElement: function() document.getElementById("v"),
checkResult: function(html) is(html.indexOf("xxx"), -1, "Should not have retained the import style")
rootElement() { return document.getElementById("v"); },
checkResult(html) { is(html.indexOf("xxx"), -1, "Should not have retained the import style"); },
},
{
id: "w",
isIFrame: true,
payload: validStyle3Payload,
rootElement: function() document.getElementById("w").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("xxx"), -1, "Should have retained the font-face style")
rootElement() { return document.getElementById("w").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("xxx"), -1, "Should have retained the font-face style"); },
},
{
id: "x",
payload: validStyle3Payload,
rootElement: function() document.getElementById("x"),
checkResult: function(html) isnot(html.indexOf("xxx"), -1, "Should have retained the font-face style")
rootElement() { return document.getElementById("x"); },
checkResult(html) { isnot(html.indexOf("xxx"), -1, "Should have retained the font-face style"); },
},
{
id: "y",
isIFrame: true,
payload: invalidStyle5Payload,
rootElement: function() document.getElementById("y").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("xxx"), -1, "Should not have retained the font-face style")
rootElement() { return document.getElementById("y").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("xxx"), -1, "Should not have retained the font-face style"); },
},
{
id: "z",
payload: invalidStyle5Payload,
rootElement: function() document.getElementById("z"),
checkResult: function(html) isnot(html.indexOf("xxx"), -1, "Should not have retained the font-face style")
rootElement() { return document.getElementById("z"); },
checkResult(html) { isnot(html.indexOf("xxx"), -1, "Should not have retained the font-face style"); },
},
{
id: "aa",
isIFrame: true,
payload: nestedStylePayload,
rootElement: function() document.getElementById("aa").contentDocument.documentElement,
rootElement() { return document.getElementById("aa").contentDocument.documentElement; },
checkResult: function(html, text) {
is(html.indexOf("binding-1"), -1, "Should not have retained the binding-1 style");
isnot(text.indexOf("#bar2"), -1, "Should have retained binding-2 as text content");
@@ -297,7 +297,7 @@ var tests = [
{
id: "bb",
payload: nestedStylePayload,
rootElement: function() document.getElementById("bb"),
rootElement() { return document.getElementById("bb"); },
checkResult: function(html, text) {
is(html.indexOf("binding-1"), -1, "Should not have retained the binding-1 style");
isnot(text.indexOf("#bar2"), -1, "Should have retained binding-2 as text content");
@@ -308,73 +308,73 @@ var tests = [
id: "cc",
isIFrame: true,
payload: validStyle4Payload,
rootElement: function() document.getElementById("cc").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("xxx"), -1, "Should have retained the namespace style")
rootElement() { return document.getElementById("cc").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("xxx"), -1, "Should have retained the namespace style"); },
},
{
id: "dd",
payload: validStyle4Payload,
rootElement: function() document.getElementById("dd"),
checkResult: function(html) isnot(html.indexOf("xxx"), -1, "Should have retained the namespace style")
rootElement() { return document.getElementById("dd"); },
checkResult(html) { isnot(html.indexOf("xxx"), -1, "Should have retained the namespace style"); },
},
{
id: "ee",
isIFrame: true,
payload: invalidStyle6Payload,
rootElement: function() document.getElementById("ee").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("xxx"), -1, "Should not have retained the namespace style")
rootElement() { return document.getElementById("ee").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("xxx"), -1, "Should not have retained the namespace style"); },
},
{
id: "ff",
payload: invalidStyle6Payload,
rootElement: function() document.getElementById("ff"),
checkResult: function(html) isnot(html.indexOf("xxx"), -1, "Should not have retained the namespace style")
rootElement() { return document.getElementById("ff"); },
checkResult(html) { isnot(html.indexOf("xxx"), -1, "Should not have retained the namespace style"); },
},
{
id: "gg",
isIFrame: true,
payload: invalidStyle6Payload,
rootElement: function() document.getElementById("gg").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("bar"), -1, "Should have retained the src attribute for the image")
rootElement() { return document.getElementById("gg").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("bar"), -1, "Should have retained the src attribute for the image"); },
},
{
id: "hh",
payload: invalidStyle6Payload,
rootElement: function() document.getElementById("hh"),
checkResult: function(html) isnot(html.indexOf("bar"), -1, "Should have retained the src attribute for the image")
rootElement() { return document.getElementById("hh"); },
checkResult(html) { isnot(html.indexOf("bar"), -1, "Should have retained the src attribute for the image"); },
},
{
id: "ii",
isIFrame: true,
payload: invalidStyle6Payload,
rootElement: function() document.getElementById("ii").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("bar"), -1, "Should have retained the src attribute for the image")
rootElement() { return document.getElementById("ii").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("bar"), -1, "Should have retained the src attribute for the image"); },
},
{
id: "jj",
payload: invalidStyle6Payload,
rootElement: function() document.getElementById("jj"),
checkResult: function(html) isnot(html.indexOf("bar"), -1, "Should have retained the src attribute for the image")
rootElement() { return document.getElementById("jj"); },
checkResult(html) { isnot(html.indexOf("bar"), -1, "Should have retained the src attribute for the image"); },
},
{
id: "kk",
isIFrame: true,
payload: invalidStyle6Payload,
rootElement: function() document.getElementById("kk").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("bar"), -1, "Should have retained the src attribute for the image")
rootElement() { return document.getElementById("kk").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("bar"), -1, "Should have retained the src attribute for the image"); },
},
{
id: "ll",
payload: invalidStyle6Payload,
rootElement: function() document.getElementById("ll"),
checkResult: function(html) isnot(html.indexOf("bar"), -1, "Should have retained the src attribute for the image")
rootElement() { return document.getElementById("ll"); },
checkResult(html) { isnot(html.indexOf("bar"), -1, "Should have retained the src attribute for the image"); },
},
{
id: "mm",
isIFrame: true,
indirectPaste: true,
payload: invalidStyle7Payload,
rootElement: function() document.getElementById("mm").contentDocument.documentElement,
rootElement() { return document.getElementById("mm").contentDocument.documentElement; },
checkResult: function(html) {
is(html.indexOf("xxx"), -1, "Should not have retained the title text");
isnot(html.indexOf("foo"), -1, "Should have retained the body text");
@@ -384,7 +384,7 @@ var tests = [
id: "nn",
indirectPaste: true,
payload: invalidStyle7Payload,
rootElement: function() document.getElementById("nn"),
rootElement() { return document.getElementById("nn"); },
checkResult: function(html) {
is(html.indexOf("xxx"), -1, "Should not have retained the title text");
isnot(html.indexOf("foo"), -1, "Should have retained the body text");
@@ -394,143 +394,143 @@ var tests = [
id: "oo",
isIFrame: true,
payload: validDataFooPayload,
rootElement: function() document.getElementById("oo").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("bar"), -1, "Should have retained the data-bar attribute")
rootElement() { return document.getElementById("oo").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("bar"), -1, "Should have retained the data-bar attribute"); },
},
{
id: "pp",
payload: validDataFooPayload,
rootElement: function() document.getElementById("pp"),
checkResult: function(html) isnot(html.indexOf("bar"), -1, "Should have retained the data-bar attribute")
rootElement() { return document.getElementById("pp"); },
checkResult(html) { isnot(html.indexOf("bar"), -1, "Should have retained the data-bar attribute"); },
},
{
id: "qq",
isIFrame: true,
payload: validDataFoo2Payload,
rootElement: function() document.getElementById("qq").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("bar"), -1, "Should have retained the _bar attribute")
rootElement() { return document.getElementById("qq").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("bar"), -1, "Should have retained the _bar attribute"); },
},
{
id: "rr",
payload: validDataFoo2Payload,
rootElement: function() document.getElementById("rr"),
checkResult: function(html) isnot(html.indexOf("bar"), -1, "Should have retained the _bar attribute")
rootElement() { return document.getElementById("rr"); },
checkResult(html) { isnot(html.indexOf("bar"), -1, "Should have retained the _bar attribute"); },
},
{
id: "ss",
isIFrame: true,
payload: invalidStyle8Payload,
rootElement: function() document.getElementById("ss").contentDocument.documentElement,
checkResult: function(html) is(html.indexOf("@-moz-document"), -1, "Should not have retained the @-moz-document rule")
rootElement() { return document.getElementById("ss").contentDocument.documentElement; },
checkResult(html) { is(html.indexOf("@-moz-document"), -1, "Should not have retained the @-moz-document rule"); },
},
{
id: "tt",
payload: invalidStyle8Payload,
rootElement: function() document.getElementById("tt"),
checkResult: function(html) is(html.indexOf("@-moz-document"), -1, "Should not have retained the @-moz-document rule")
rootElement() { return document.getElementById("tt"); },
checkResult(html) { is(html.indexOf("@-moz-document"), -1, "Should not have retained the @-moz-document rule"); },
},
{
id: "uu",
isIFrame: true,
payload: invalidStyle9Payload,
rootElement: function() document.getElementById("uu").contentDocument.documentElement,
checkResult: function(html) is(html.indexOf("@-moz-keyframes"), -1, "Should not have retained the @-moz-keyframes rule")
rootElement() { return document.getElementById("uu").contentDocument.documentElement; },
checkResult(html) { is(html.indexOf("@-moz-keyframes"), -1, "Should not have retained the @-moz-keyframes rule"); },
},
{
id: "vv",
payload: invalidStyle9Payload,
rootElement: function() document.getElementById("vv"),
checkResult: function(html) is(html.indexOf("@-moz-keyframes"), -1, "Should not have retained the @-moz-keyframes rule")
rootElement() { return document.getElementById("vv"); },
checkResult(html) { is(html.indexOf("@-moz-keyframes"), -1, "Should not have retained the @-moz-keyframes rule"); },
},
{
id: "sss",
payload: svgPayload,
rootElement: function() document.getElementById("sss"),
checkResult: function(html) isnot(html.indexOf("svgtitle"), -1, "Should have retained SVG title")
rootElement() { return document.getElementById("sss"); },
checkResult(html) { isnot(html.indexOf("svgtitle"), -1, "Should have retained SVG title"); },
},
{
id: "ssss",
isIFrame: true,
payload: svgPayload,
rootElement: function() document.getElementById("ssss").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("svgtitle"), -1, "Should have retained SVG title")
rootElement() { return document.getElementById("ssss").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("svgtitle"), -1, "Should have retained SVG title"); },
},
{
id: "ttt",
payload: svg2Payload,
rootElement: function() document.getElementById("ttt"),
checkResult: function(html) is(html.indexOf("bogussvg"), -1, "Should have dropped bogussvg element")
rootElement() { return document.getElementById("ttt"); },
checkResult(html) { is(html.indexOf("bogussvg"), -1, "Should have dropped bogussvg element"); },
},
{
id: "tttt",
isIFrame: true,
payload: svg2Payload,
rootElement: function() document.getElementById("tttt").contentDocument.documentElement,
checkResult: function(html) is(html.indexOf("bogussvg"), -1, "Should have dropped bogussvg element")
rootElement() { return document.getElementById("tttt").contentDocument.documentElement; },
checkResult(html) { is(html.indexOf("bogussvg"), -1, "Should have dropped bogussvg element"); },
},
{
id: "uuu",
payload: mathPayload,
rootElement: function() document.getElementById("uuu"),
checkResult: function(html) is(html.indexOf("bogusmath"), -1, "Should have dropped bogusmath element")
rootElement() { return document.getElementById("uuu"); },
checkResult(html) { is(html.indexOf("bogusmath"), -1, "Should have dropped bogusmath element"); },
},
{
id: "uuuu",
isIFrame: true,
payload: mathPayload,
rootElement: function() document.getElementById("uuuu").contentDocument.documentElement,
checkResult: function(html) is(html.indexOf("bogusmath"), -1, "Should have dropped bogusmath element")
rootElement() { return document.getElementById("uuuu").contentDocument.documentElement; },
checkResult(html) { is(html.indexOf("bogusmath"), -1, "Should have dropped bogusmath element"); },
},
{
id: "vvv",
payload: math2Payload,
rootElement: function() document.getElementById("vvv"),
checkResult: function(html) is(html.indexOf("yyy.css"), -1, "Should have dropped MathML style element")
rootElement() { return document.getElementById("vvv"); },
checkResult(html) { is(html.indexOf("yyy.css"), -1, "Should have dropped MathML style element"); },
},
{
id: "vvvv",
isIFrame: true,
payload: math2Payload,
rootElement: function() document.getElementById("vvvv").contentDocument.documentElement,
checkResult: function(html) is(html.indexOf("yyy.css"), -1, "Should have dropped MathML style element")
rootElement() { return document.getElementById("vvvv").contentDocument.documentElement; },
checkResult(html) { is(html.indexOf("yyy.css"), -1, "Should have dropped MathML style element"); },
},
{
id: "www",
payload: math3Payload,
rootElement: function() document.getElementById("www"),
checkResult: function(html) isnot(html.indexOf("<mi"), -1, "Should not have dropped MathML mi element")
rootElement() { return document.getElementById("www"); },
checkResult(html) { isnot(html.indexOf("<mi"), -1, "Should not have dropped MathML mi element"); },
},
{
id: "wwww",
isIFrame: true,
payload: math3Payload,
rootElement: function() document.getElementById("wwww").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("<mi"), -1, "Should not have dropped MathML mi element")
rootElement() { return document.getElementById("wwww").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("<mi"), -1, "Should not have dropped MathML mi element"); },
},
{
id: "xxx",
payload: videoPayload,
rootElement: function() document.getElementById("xxx"),
checkResult: function(html) isnot(html.indexOf("controls="), -1, "Should have added the controls attribute")
rootElement() { return document.getElementById("xxx"); },
checkResult(html) { isnot(html.indexOf("controls="), -1, "Should have added the controls attribute"); },
},
{
id: "xxxx",
isIFrame: true,
payload: videoPayload,
rootElement: function() document.getElementById("xxxx").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("controls="), -1, "Should have added the controls attribute")
rootElement() { return document.getElementById("xxxx").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("controls="), -1, "Should have added the controls attribute"); },
},
{
id: "yyy",
payload: microdataPayload,
rootElement: function() document.getElementById("yyy"),
rootElement() { return document.getElementById("yyy"); },
checkResult: function(html) { is(html.indexOf("name"), -1, "Should have dropped name."); is(html.indexOf("rel"), -1, "Should have dropped rel."); isnot(html.indexOf("itemprop"), -1, "Should not have dropped itemprop."); }
},
{
id: "yyyy",
isIFrame: true,
payload: microdataPayload,
rootElement: function() document.getElementById("yyyy").contentDocument.documentElement,
rootElement() { return document.getElementById("yyyy").contentDocument.documentElement; },
checkResult: function(html) { is(html.indexOf("name"), -1, "Should have dropped name."); is(html.indexOf("rel"), -1, "Should have dropped rel."); isnot(html.indexOf("itemprop"), -1, "Should not have dropped itemprop."); }
}
];
+1 -1
View File
@@ -34,7 +34,7 @@ function testTab(prefix, callback) {
function() {
dst.focus();
var inputReceived = false;
dst.addEventListener("input", function() inputReceived = true, false);
dst.addEventListener("input", function() { inputReceived = true; }, false);
synthesizeKey("v", {accelKey: true});
ok(inputReceived, "An input event should be raised");
is(dst.value, prefix + src.value, "The value should be pasted verbatim");
+1 -1
View File
@@ -23,7 +23,7 @@ SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
var i = document.querySelector("input");
var inputCount = 0;
i.addEventListener("input", function() inputCount++, false);
i.addEventListener("input", function() { inputCount++; }, false);
// test cut
i.focus();
+185 -14
View File
@@ -11,6 +11,7 @@
#include "Rect.h"
#include "ScaledFontMac.h"
#include "Tools.h"
#include "PathHelpers.h"
#include <vector>
#include <algorithm>
#include "MacIOSurface.h"
@@ -992,13 +993,162 @@ DrawTargetCG::FillRect(const Rect &aRect,
CGContextRestoreGState(mCg);
}
void
DrawTargetCG::StrokeLine(const Point &p1, const Point &p2, const Pattern &aPattern, const StrokeOptions &aStrokeOptions, const DrawOptions &aDrawOptions)
static Float
DashPeriodLength(const StrokeOptions& aStrokeOptions)
{
if (!std::isfinite(p1.x) ||
!std::isfinite(p1.y) ||
!std::isfinite(p2.x) ||
!std::isfinite(p2.y)) {
Float length = 0;
for (size_t i = 0; i < aStrokeOptions.mDashLength; i++) {
length += aStrokeOptions.mDashPattern[i];
}
if (aStrokeOptions.mDashLength & 1) {
// "If an odd number of values is provided, then the list of values is
// repeated to yield an even number of values."
// Double the length.
length += length;
}
return length;
}
inline Float
RoundDownToMultiple(Float aValue, Float aFactor)
{
return floorf(aValue / aFactor) * aFactor;
}
static Rect
UserSpaceStrokeClip(const Rect &aDeviceClip,
const Matrix &aTransform,
const StrokeOptions &aStrokeOptions)
{
Matrix inverse = aTransform;
if (!inverse.Invert()) {
return Rect();
}
Rect deviceClip = aDeviceClip;
deviceClip.Inflate(MaxStrokeExtents(aStrokeOptions, aTransform));
return inverse.TransformBounds(deviceClip);
}
static Rect
ShrinkClippedStrokedRect(const Rect &aStrokedRect, const Rect &aDeviceClip,
const Matrix &aTransform,
const StrokeOptions &aStrokeOptions)
{
Rect userSpaceStrokeClip =
UserSpaceStrokeClip(aDeviceClip, aTransform, aStrokeOptions);
Rect intersection = aStrokedRect.Intersect(userSpaceStrokeClip);
Float dashPeriodLength = DashPeriodLength(aStrokeOptions);
if (intersection.IsEmpty() || dashPeriodLength == 0.0f) {
return intersection;
}
// Reduce the rectangle side lengths in multiples of the dash period length
// so that the visible dashes stay in the same place.
Margin insetBy = aStrokedRect - intersection;
insetBy.top = RoundDownToMultiple(insetBy.top, dashPeriodLength);
insetBy.right = RoundDownToMultiple(insetBy.right, dashPeriodLength);
insetBy.bottom = RoundDownToMultiple(insetBy.bottom, dashPeriodLength);
insetBy.left = RoundDownToMultiple(insetBy.left, dashPeriodLength);
Rect shrunkRect = aStrokedRect;
shrunkRect.Deflate(insetBy);
return shrunkRect;
}
// Liang-Barsky
// This algorithm was chosen for its code brevity, with the hope that its
// performance is good enough.
// Sets aStart and aEnd to floats between 0 and the line length, or returns
// false if the line is completely outside the rect.
static bool
IntersectLineWithRect(const Point& aP1, const Point& aP2, const Rect& aClip,
Float* aStart, Float* aEnd)
{
Float t0 = 0.0f;
Float t1 = 1.0f;
Point vector = aP2 - aP1;
for (uint32_t edge = 0; edge < 4; edge++) {
Float p, q;
switch (edge) {
case 0: p = -vector.x; q = aP1.x - aClip.x; break;
case 1: p = vector.x; q = aClip.XMost() - aP1.x; break;
case 2: p = -vector.y; q = aP1.y - aClip.y; break;
case 3: p = vector.y; q = aClip.YMost() - aP1.y; break;
}
if (p == 0.0f) {
// Line is parallel to the edge.
if (q < 0.0f) {
return false;
}
continue;
}
Float r = q / p;
if (p < 0) {
t0 = std::max(t0, r);
} else {
t1 = std::min(t1, r);
}
if (t0 > t1) {
return false;
}
}
Float length = vector.Length();
*aStart = t0 * length;
*aEnd = t1 * length;
return true;
}
// Adjusts aP1 and aP2 to a shrunk line, or returns false if the line is
// completely outside the clip.
static bool
ShrinkClippedStrokedLine(Point &aP1, Point& aP2, const Rect &aDeviceClip,
const Matrix &aTransform,
const StrokeOptions &aStrokeOptions)
{
Rect userSpaceStrokeClip =
UserSpaceStrokeClip(aDeviceClip, aTransform, aStrokeOptions);
Point vector = aP2 - aP1;
Float length = vector.Length();
if (length == 0.0f) {
return true;
}
Float start = 0;
Float end = length;
if (!IntersectLineWithRect(aP1, aP2, userSpaceStrokeClip, &start, &end)) {
return false;
}
Float dashPeriodLength = DashPeriodLength(aStrokeOptions);
if (dashPeriodLength > 0.0f) {
// Shift the line points by multiples of dashPeriodLength so that the
// dashes stay in the same place.
start = RoundDownToMultiple(start, dashPeriodLength);
end = length - RoundDownToMultiple(length - end, dashPeriodLength);
}
Point startPoint = aP1;
aP1 = Point(startPoint.x + start * vector.x / length,
startPoint.y + start * vector.y / length);
aP2 = Point(startPoint.x + end * vector.x / length,
startPoint.y + end * vector.y / length);
return true;
}
void
DrawTargetCG::StrokeLine(const Point &aP1, const Point &aP2, const Pattern &aPattern, const StrokeOptions &aStrokeOptions, const DrawOptions &aDrawOptions)
{
if (!std::isfinite(aP1.x) ||
!std::isfinite(aP1.y) ||
!std::isfinite(aP2.x) ||
!std::isfinite(aP2.y)) {
return;
}
@@ -1006,6 +1156,14 @@ DrawTargetCG::StrokeLine(const Point &p1, const Point &p2, const Pattern &aPatte
return;
}
Point p1 = aP1;
Point p2 = aP2;
Rect deviceClip(0, 0, mSize.width, mSize.height);
if (!ShrinkClippedStrokedLine(p1, p2, deviceClip, mTransform, aStrokeOptions)) {
return;
}
MarkChanged();
CGContextSaveGState(mCg);
@@ -1080,6 +1238,20 @@ DrawTargetCG::StrokeRect(const Rect &aRect,
if (MOZ2D_ERROR_IF(!cg)) {
return;
}
// Stroking large rectangles with dashes is expensive with CG (fixed
// overhead based on the number of dashes, regardless of whether the dashes
// are visible), so we try to reduce the size of the stroked rectangle as
// much as possible before passing it on to CG.
Rect rect = aRect;
if (!rect.IsEmpty()) {
Rect deviceClip(0, 0, mSize.width, mSize.height);
rect = ShrinkClippedStrokedRect(rect, deviceClip, mTransform, aStrokeOptions);
if (rect.IsEmpty()) {
return;
}
}
CGContextSetAlpha(mCg, aDrawOptions.mAlpha);
CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp));
@@ -1091,7 +1263,7 @@ DrawTargetCG::StrokeRect(const Rect &aRect,
bool pixelAlignedStroke = mTransform.IsAllIntegers() &&
mTransform.PreservesAxisAlignedRectangles() &&
aPattern.GetType() == PatternType::COLOR &&
IsPixelAlignedStroke(aRect, aStrokeOptions.mLineWidth);
IsPixelAlignedStroke(rect, aStrokeOptions.mLineWidth);
CGContextSetShouldAntialias(cg,
aDrawOptions.mAntialiasMode != AntialiasMode::NONE && !pixelAlignedStroke);
@@ -1102,7 +1274,7 @@ DrawTargetCG::StrokeRect(const Rect &aRect,
if (isGradient(aPattern)) {
// There's no CGContextClipStrokeRect so we do it by hand
CGContextBeginPath(cg);
CGContextAddRect(cg, RectToCGRect(aRect));
CGContextAddRect(cg, RectToCGRect(rect));
CGContextReplacePathWithStrokedPath(cg);
CGRect extents = CGContextGetPathBoundingBox(cg);
//XXX: should we use EO clip here?
@@ -1110,17 +1282,16 @@ DrawTargetCG::StrokeRect(const Rect &aRect,
DrawGradient(mColorSpace, cg, aPattern, extents);
} else {
SetStrokeFromPattern(cg, mColorSpace, aPattern);
// We'd like to use CGContextStrokeRect(cg, RectToCGRect(aRect));
// We'd like to use CGContextStrokeRect(cg, RectToCGRect(rect));
// Unfortunately, newer versions of OS X no longer start at the top-left
// corner and stroke clockwise as older OS X versions and all the other
// Moz2D backends do. (Newer versions start at the top right-hand corner
// and stroke counter-clockwise.) For consistency we draw the rect by hand.
CGRect rect = RectToCGRect(aRect);
CGContextBeginPath(cg);
CGContextMoveToPoint(cg, CGRectGetMinX(rect), CGRectGetMinY(rect));
CGContextAddLineToPoint(cg, CGRectGetMaxX(rect), CGRectGetMinY(rect));
CGContextAddLineToPoint(cg, CGRectGetMaxX(rect), CGRectGetMaxY(rect));
CGContextAddLineToPoint(cg, CGRectGetMinX(rect), CGRectGetMaxY(rect));
CGContextMoveToPoint(cg, rect.x, rect.y);
CGContextAddLineToPoint(cg, rect.XMost(), rect.y);
CGContextAddLineToPoint(cg, rect.XMost(), rect.YMost());
CGContextAddLineToPoint(cg, rect.x, rect.YMost());
CGContextClosePath(cg);
CGContextStrokePath(cg);
}
+48 -35
View File
@@ -3,11 +3,9 @@
* 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/. */
#define _USE_MATH_DEFINES
#include <cmath>
#include "DrawTargetTiled.h"
#include "Logging.h"
#include "PathHelpers.h"
using namespace std;
@@ -107,8 +105,6 @@ TILED_COMMAND(Flush)
TILED_COMMAND4(DrawFilter, FilterNode*, const Rect&, const Point&, const DrawOptions&)
TILED_COMMAND1(ClearRect, const Rect&)
TILED_COMMAND4(MaskSurface, const Pattern&, SourceSurface*, Point, const DrawOptions&)
TILED_COMMAND4(StrokeRect, const Rect&, const Pattern&, const StrokeOptions&, const DrawOptions&)
TILED_COMMAND5(StrokeLine, const Point&, const Point&, const Pattern&, const StrokeOptions&, const DrawOptions&)
TILED_COMMAND5(FillGlyphs, ScaledFont*, const GlyphBuffer&, const Pattern&, const DrawOptions&, const GlyphRenderingOptions*)
TILED_COMMAND3(Mask, const Pattern&, const Pattern&, const DrawOptions&)
@@ -232,40 +228,12 @@ DrawTargetTiled::FillRect(const Rect& aRect, const Pattern& aPattern, const Draw
}
}
// The logic for this comes from _cairo_stroke_style_max_distance_from_path
static Rect
PathExtentsToMaxStrokeExtents(const StrokeOptions &aStrokeOptions,
const Rect &aRect,
const Matrix &aTransform)
{
double styleExpansionFactor = 0.5f;
if (aStrokeOptions.mLineCap == CapStyle::SQUARE) {
styleExpansionFactor = M_SQRT1_2;
}
if (aStrokeOptions.mLineJoin == JoinStyle::MITER &&
styleExpansionFactor < M_SQRT2 * aStrokeOptions.mMiterLimit) {
styleExpansionFactor = M_SQRT2 * aStrokeOptions.mMiterLimit;
}
styleExpansionFactor *= aStrokeOptions.mLineWidth;
double dx = styleExpansionFactor * hypot(aTransform._11, aTransform._21);
double dy = styleExpansionFactor * hypot(aTransform._22, aTransform._12);
Rect result = aRect;
result.Inflate(dx, dy);
return result;
}
void
DrawTargetTiled::Stroke(const Path* aPath, const Pattern& aPattern, const StrokeOptions& aStrokeOptions, const DrawOptions& aDrawOptions)
{
// Approximate the stroke extents, since Path::GetStrokeExtents can be slow
Rect deviceRect = PathExtentsToMaxStrokeExtents(aStrokeOptions,
aPath->GetBounds(mTransform),
mTransform);
Rect deviceRect = aPath->GetBounds(mTransform);
deviceRect.Inflate(MaxStrokeExtents(aStrokeOptions, mTransform));
for (size_t i = 0; i < mTiles.size(); i++) {
if (!mTiles[i].mClippedOut &&
deviceRect.Intersects(Rect(mTiles[i].mTileOrigin.x,
@@ -277,6 +245,51 @@ DrawTargetTiled::Stroke(const Path* aPath, const Pattern& aPattern, const Stroke
}
}
void
DrawTargetTiled::StrokeRect(const Rect& aRect, const Pattern& aPattern, const StrokeOptions &aStrokeOptions, const DrawOptions& aDrawOptions)
{
Rect deviceRect = mTransform.TransformBounds(aRect);
Margin strokeMargin = MaxStrokeExtents(aStrokeOptions, mTransform);
Rect outerRect = deviceRect;
outerRect.Inflate(strokeMargin);
Rect innerRect;
if (mTransform.IsRectilinear()) {
// If rects are mapped to rects, we can compute the inner rect
// of the stroked rect.
innerRect = deviceRect;
innerRect.Deflate(strokeMargin);
}
for (size_t i = 0; i < mTiles.size(); i++) {
if (mTiles[i].mClippedOut) {
continue;
}
Rect tileRect(mTiles[i].mTileOrigin.x,
mTiles[i].mTileOrigin.y,
mTiles[i].mDrawTarget->GetSize().width,
mTiles[i].mDrawTarget->GetSize().height);
if (outerRect.Intersects(tileRect) && !innerRect.Contains(tileRect)) {
mTiles[i].mDrawTarget->StrokeRect(aRect, aPattern, aStrokeOptions, aDrawOptions);
}
}
}
void
DrawTargetTiled::StrokeLine(const Point& aStart, const Point& aEnd, const Pattern& aPattern, const StrokeOptions &aStrokeOptions, const DrawOptions& aDrawOptions)
{
Rect lineBounds = Rect(aStart, Size()).UnionEdges(Rect(aEnd, Size()));
Rect deviceRect = mTransform.TransformBounds(lineBounds);
deviceRect.Inflate(MaxStrokeExtents(aStrokeOptions, mTransform));
for (size_t i = 0; i < mTiles.size(); i++) {
if (!mTiles[i].mClippedOut &&
deviceRect.Intersects(Rect(mTiles[i].mTileOrigin.x,
mTiles[i].mTileOrigin.y,
mTiles[i].mDrawTarget->GetSize().width,
mTiles[i].mDrawTarget->GetSize().height))) {
mTiles[i].mDrawTarget->StrokeLine(aStart, aEnd, aPattern, aStrokeOptions, aDrawOptions);
}
}
}
void
DrawTargetTiled::Fill(const Path* aPath, const Pattern& aPattern, const DrawOptions& aDrawOptions)
{
+26
View File
@@ -3,6 +3,9 @@
* 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/. */
#define _USE_MATH_DEFINES
#include <cmath>
#include "PathHelpers.h"
namespace mozilla {
@@ -238,6 +241,29 @@ StrokeSnappedEdgesOfRect(const Rect& aRect, DrawTarget& aDrawTarget,
aDrawTarget.StrokeLine(p1, p2, aColor, aStrokeOptions);
}
// The logic for this comes from _cairo_stroke_style_max_distance_from_path
Margin
MaxStrokeExtents(const StrokeOptions& aStrokeOptions,
const Matrix& aTransform)
{
double styleExpansionFactor = 0.5f;
if (aStrokeOptions.mLineCap == CapStyle::SQUARE) {
styleExpansionFactor = M_SQRT1_2;
}
if (aStrokeOptions.mLineJoin == JoinStyle::MITER &&
styleExpansionFactor < M_SQRT2 * aStrokeOptions.mMiterLimit) {
styleExpansionFactor = M_SQRT2 * aStrokeOptions.mMiterLimit;
}
styleExpansionFactor *= aStrokeOptions.mLineWidth;
double dx = styleExpansionFactor * hypot(aTransform._11, aTransform._21);
double dy = styleExpansionFactor * hypot(aTransform._22, aTransform._12);
return Margin(dy, dx, dy, dx);
}
} // namespace gfx
} // namespace mozilla
+10
View File
@@ -307,6 +307,16 @@ GFX2D_API void StrokeSnappedEdgesOfRect(const Rect& aRect,
const ColorPattern& aColor,
const StrokeOptions& aStrokeOptions);
/**
* Return the margin, in device space, by which a stroke can extend beyond the
* rendered shape.
* @param aStrokeOptions The stroke options that the stroke is drawn with.
* @param aTransform The user space to device space transform.
* @return The stroke margin.
*/
GFX2D_API Margin MaxStrokeExtents(const StrokeOptions& aStrokeOptions,
const Matrix& aTransform);
extern UserDataKey sDisablePixelSnapping;
/**
+2 -2
View File
@@ -115,6 +115,7 @@ UNIFIED_SOURCES += [
'DrawTargetCapture.cpp',
'DrawTargetDual.cpp',
'DrawTargetRecording.cpp',
'DrawTargetTiled.cpp',
'Factory.cpp',
'FilterNodeSoftware.cpp',
'FilterProcessing.cpp',
@@ -123,7 +124,6 @@ UNIFIED_SOURCES += [
'Matrix.cpp',
'Path.cpp',
'PathCairo.cpp',
'PathHelpers.cpp',
'PathRecording.cpp',
'RecordedEvent.cpp',
'Scale.cpp',
@@ -134,7 +134,7 @@ UNIFIED_SOURCES += [
]
SOURCES += [
'DrawTargetTiled.cpp',
'PathHelpers.cpp', # Uses _USE_MATH_DEFINES
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
-17
View File
@@ -277,21 +277,6 @@ struct ParamTraits<mozilla::layers::TextureFlags>
mozilla::layers::TextureFlags::ALL_BITS>
{};
template <>
struct ParamTraits<mozilla::layers::TextureIdentifier>
: public ContiguousEnumSerializer<
mozilla::layers::TextureIdentifier,
mozilla::layers::TextureIdentifier::Front,
mozilla::layers::TextureIdentifier::HighBound>
{};
template <>
struct ParamTraits<mozilla::layers::DeprecatedTextureHostFlags>
: public BitFlagsEnumSerializer<
mozilla::layers::DeprecatedTextureHostFlags,
mozilla::layers::DeprecatedTextureHostFlags::ALL_BITS>
{};
template <>
struct ParamTraits<mozilla::layers::DiagnosticTypes>
: public BitFlagsEnumSerializer<
@@ -850,14 +835,12 @@ struct ParamTraits<mozilla::layers::TextureInfo>
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.mCompositableType);
WriteParam(aMsg, aParam.mDeprecatedTextureHostFlags);
WriteParam(aMsg, aParam.mTextureFlags);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
return ReadParam(aMsg, aIter, &aResult->mCompositableType) &&
ReadParam(aMsg, aIter, &aResult->mDeprecatedTextureHostFlags) &&
ReadParam(aMsg, aIter, &aResult->mTextureFlags);
}
};
-34
View File
@@ -133,8 +133,6 @@ enum class EffectTypes : uint8_t {
*/
enum class CompositableType : uint8_t {
UNKNOWN,
CONTENT_INC, // painted layer interface, only sends incremental
// updates to a texture on the compositor side.
CONTENT_TILED, // tiled painted layer
IMAGE, // image with single buffering
IMAGE_OVERLAY, // image without buffer
@@ -144,19 +142,6 @@ enum class CompositableType : uint8_t {
COUNT
};
/**
* How the texture host is used for composition,
* XXX - Only used by ContentClientIncremental
*/
enum class DeprecatedTextureHostFlags : uint8_t {
DEFAULT = 0, // The default texture host for the given SurfaceDescriptor
TILED = 1 << 0, // A texture host that supports tiling
COPY_PREVIOUS = 1 << 1, // Texture contents should be initialized
// from the previous texture.
ALL_BITS = (1 << 2) - 1
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(DeprecatedTextureHostFlags)
#ifdef XP_WIN
typedef void* SyncHandle;
#else
@@ -194,20 +179,6 @@ struct TextureFactoryIdentifier
{}
};
/**
* Identify a texture to a compositable. Many textures can have the same id, but
* the id is unique for any texture owned by a particular compositable.
* XXX - We don't really need this, it will be removed along with the incremental
* ContentClient/Host.
*/
enum class TextureIdentifier : uint8_t {
Front = 1,
Back = 2,
OnWhiteFront = 3,
OnWhiteBack = 4,
HighBound
};
/**
* Information required by the compositor from the content-side for creating or
* using compositables and textures.
@@ -218,27 +189,22 @@ enum class TextureIdentifier : uint8_t {
struct TextureInfo
{
CompositableType mCompositableType;
// XXX - only used by ContentClientIncremental
DeprecatedTextureHostFlags mDeprecatedTextureHostFlags;
TextureFlags mTextureFlags;
TextureInfo()
: mCompositableType(CompositableType::UNKNOWN)
, mDeprecatedTextureHostFlags(DeprecatedTextureHostFlags::DEFAULT)
, mTextureFlags(TextureFlags::NO_FLAGS)
{}
explicit TextureInfo(CompositableType aType,
TextureFlags aTextureFlags = TextureFlags::DEFAULT)
: mCompositableType(aType)
, mDeprecatedTextureHostFlags(DeprecatedTextureHostFlags::DEFAULT)
, mTextureFlags(aTextureFlags)
{}
bool operator==(const TextureInfo& aOther) const
{
return mCompositableType == aOther.mCompositableType &&
mDeprecatedTextureHostFlags == aOther.mDeprecatedTextureHostFlags &&
mTextureFlags == aOther.mTextureFlags;
}
};
-1
View File
@@ -272,7 +272,6 @@ public:
struct DrawIterator {
friend class RotatedContentBuffer;
friend class ContentClientIncremental;
DrawIterator()
: mCount(0)
{}
-2
View File
@@ -53,8 +53,6 @@ public:
nsIntRegion* aDestRegion = nullptr,
gfx::IntPoint* aSrcOffset = nullptr) override
{
// XXX - For this to work with IncrementalContentHost we will need to support
// the aDestRegion and aSrcOffset parameters properly;
mSurface = aSurface;
return true;
}
-11
View File
@@ -594,17 +594,6 @@ ClientLayerManager::ForwardTransaction(bool aScheduleComposite)
break;
}
case EditReply::TOpTextureSwap: {
MOZ_LAYERS_LOG(("[LayersForwarder] TextureSwap"));
const OpTextureSwap& ots = reply.get_OpTextureSwap();
CompositableClient* compositable =
CompositableClient::FromIPDLActor(ots.compositableChild());
MOZ_ASSERT(compositable);
compositable->SetDescriptorFromReply(ots.textureId(), ots.image());
break;
}
case EditReply::TReturnReleaseFence: {
const ReturnReleaseFence& rep = reply.get_ReturnReleaseFence();
FenceHandle fence = rep.fence();
-6
View File
@@ -143,12 +143,6 @@ public:
TextureFlags aTextureFlags,
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT);
virtual void SetDescriptorFromReply(TextureIdentifier aTextureId,
const SurfaceDescriptor& aDescriptor)
{
MOZ_CRASH("If you want to call this, you should have implemented it");
}
/**
* Establishes the connection with compositor side through IPDL
*/
-362
View File
@@ -93,11 +93,6 @@ ContentClient::CreateContentClient(CompositableForwarder* aForwarder)
if (useDoubleBuffering || PR_GetEnv("MOZ_FORCE_DOUBLE_BUFFERING")) {
return MakeAndAddRef<ContentClientDoubleBuffered>(aForwarder);
}
#ifdef XP_MACOSX
if (backend == LayersBackend::LAYERS_OPENGL) {
return MakeAndAddRef<ContentClientIncremental>(aForwarder);
}
#endif
return MakeAndAddRef<ContentClientSingleBuffered>(aForwarder);
}
@@ -673,362 +668,5 @@ ContentClientSingleBuffered::FinalizeFrame(const nsIntRegion& aRegionToDraw)
}
}
static void
WrapRotationAxis(int32_t* aRotationPoint, int32_t aSize)
{
if (*aRotationPoint < 0) {
*aRotationPoint += aSize;
} else if (*aRotationPoint >= aSize) {
*aRotationPoint -= aSize;
}
}
static void
FillSurface(DrawTarget* aDT, const nsIntRegion& aRegion,
const nsIntPoint& aOffset, const gfxRGBA& aColor)
{
nsIntRegionRectIterator iter(aRegion);
const nsIntRect* r;
while ((r = iter.Next()) != nullptr) {
aDT->FillRect(Rect(r->x - aOffset.x, r->y - aOffset.y,
r->width, r->height),
ColorPattern(ToColor(aColor)));
}
}
void
ContentClientIncremental::NotifyBufferCreated(ContentType aType, TextureFlags aFlags)
{
mTextureInfo.mTextureFlags = aFlags;
mContentType = aType;
mForwarder->CreatedIncrementalBuffer(this,
mTextureInfo,
mBufferRect);
}
RotatedContentBuffer::PaintState
ContentClientIncremental::BeginPaintBuffer(PaintedLayer* aLayer,
uint32_t aFlags)
{
mTextureInfo.mDeprecatedTextureHostFlags = DeprecatedTextureHostFlags::DEFAULT;
PaintState result;
// We need to disable rotation if we're going to be resampled when
// drawing, because we might sample across the rotation boundary.
bool canHaveRotation = !(aFlags & RotatedContentBuffer::PAINT_WILL_RESAMPLE);
nsIntRegion validRegion = aLayer->GetValidRegion();
bool canUseOpaqueSurface = aLayer->CanUseOpaqueSurface();
ContentType contentType =
canUseOpaqueSurface ? gfxContentType::COLOR :
gfxContentType::COLOR_ALPHA;
SurfaceMode mode;
nsIntRegion neededRegion;
bool canReuseBuffer;
nsIntRect destBufferRect;
while (true) {
mode = aLayer->GetSurfaceMode();
neededRegion = aLayer->GetVisibleRegion();
// If we're going to resample, we need a buffer that's in clamp mode.
canReuseBuffer = neededRegion.GetBounds().Size() <= mBufferRect.Size() &&
mHasBuffer && !(aFlags & RotatedContentBuffer::PAINT_WILL_RESAMPLE);
if (canReuseBuffer) {
if (mBufferRect.Contains(neededRegion.GetBounds())) {
// We don't need to adjust mBufferRect.
destBufferRect = mBufferRect;
} else {
// The buffer's big enough but doesn't contain everything that's
// going to be visible. We'll move it.
destBufferRect = nsIntRect(neededRegion.GetBounds().TopLeft(), mBufferRect.Size());
}
} else {
destBufferRect = neededRegion.GetBounds();
}
if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
if (!gfxPrefs::ComponentAlphaEnabled() ||
!aLayer->GetParent() ||
!aLayer->GetParent()->SupportsComponentAlphaChildren()) {
mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
} else {
contentType = gfxContentType::COLOR;
}
}
if ((aFlags & RotatedContentBuffer::PAINT_WILL_RESAMPLE) &&
(!neededRegion.GetBounds().IsEqualInterior(destBufferRect) ||
neededRegion.GetNumRects() > 1)) {
// The area we add to neededRegion might not be painted opaquely
if (mode == SurfaceMode::SURFACE_OPAQUE) {
contentType = gfxContentType::COLOR_ALPHA;
mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
}
// For component alpha layers, we leave contentType as gfxContentType::COLOR.
// We need to validate the entire buffer, to make sure that only valid
// pixels are sampled
neededRegion = destBufferRect;
}
if (mHasBuffer &&
(mContentType != contentType ||
(mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) != mHasBufferOnWhite)) {
#ifdef MOZ_DUMP_PAINTING
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
if (mContentType != contentType) {
printf_stderr("Layer's content type has changed\n");
}
if ((mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) != mHasBufferOnWhite) {
printf_stderr("Layer's component alpha status has changed\n");
}
printf_stderr("Invalidating entire layer %p: no buffer, or content type or component alpha changed\n", aLayer);
}
#endif
// We're effectively clearing the valid region, so we need to draw
// the entire needed region now.
result.mRegionToInvalidate = aLayer->GetValidRegion();
validRegion.SetEmpty();
mHasBuffer = false;
mHasBufferOnWhite = false;
mBufferRect.SetRect(0, 0, 0, 0);
mBufferRotation.MoveTo(0, 0);
// Restart decision process with the cleared buffer. We can only go
// around the loop one more iteration, since mTexImage is null now.
continue;
}
break;
}
result.mRegionToDraw.Sub(neededRegion, validRegion);
if (result.mRegionToDraw.IsEmpty())
return result;
if (destBufferRect.width > mForwarder->GetMaxTextureSize() ||
destBufferRect.height > mForwarder->GetMaxTextureSize()) {
return result;
}
// BlitTextureImage depends on the FBO texture target being
// TEXTURE_2D. This isn't the case on some older X1600-era Radeons.
if (!mForwarder->SupportsTextureBlitting() ||
!mForwarder->SupportsPartialUploads()) {
result.mRegionToDraw = neededRegion;
validRegion.SetEmpty();
mHasBuffer = false;
mHasBufferOnWhite = false;
mBufferRect.SetRect(0, 0, 0, 0);
mBufferRotation.MoveTo(0, 0);
canReuseBuffer = false;
}
nsIntRect drawBounds = result.mRegionToDraw.GetBounds();
bool createdBuffer = false;
TextureFlags bufferFlags = TextureFlags::NO_FLAGS;
if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
bufferFlags |= TextureFlags::COMPONENT_ALPHA;
}
if (canReuseBuffer) {
nsIntRect keepArea;
if (keepArea.IntersectRect(destBufferRect, mBufferRect)) {
// Set mBufferRotation so that the pixels currently in mBuffer
// will still be rendered in the right place when mBufferRect
// changes to destBufferRect.
nsIntPoint newRotation = mBufferRotation +
(destBufferRect.TopLeft() - mBufferRect.TopLeft());
WrapRotationAxis(&newRotation.x, mBufferRect.width);
WrapRotationAxis(&newRotation.y, mBufferRect.height);
NS_ASSERTION(nsIntRect(nsIntPoint(0,0), mBufferRect.Size()).Contains(newRotation),
"newRotation out of bounds");
int32_t xBoundary = destBufferRect.XMost() - newRotation.x;
int32_t yBoundary = destBufferRect.YMost() - newRotation.y;
if ((drawBounds.x < xBoundary && xBoundary < drawBounds.XMost()) ||
(drawBounds.y < yBoundary && yBoundary < drawBounds.YMost()) ||
(newRotation != nsIntPoint(0,0) && !canHaveRotation)) {
// The stuff we need to redraw will wrap around an edge of the
// buffer, so we will need to do a self-copy
// If mBufferRotation == nsIntPoint(0,0) we could do a real
// self-copy but we're not going to do that in GL yet.
// We can't do a real self-copy because the buffer is rotated.
// So allocate a new buffer for the destination.
destBufferRect = neededRegion.GetBounds();
createdBuffer = true;
} else {
mBufferRect = destBufferRect;
mBufferRotation = newRotation;
}
} else {
// No pixels are going to be kept. The whole visible region
// will be redrawn, so we don't need to copy anything, so we don't
// set destBuffer.
mBufferRect = destBufferRect;
mBufferRotation = nsIntPoint(0,0);
}
} else {
// The buffer's not big enough, so allocate a new one
createdBuffer = true;
}
NS_ASSERTION(!(aFlags & RotatedContentBuffer::PAINT_WILL_RESAMPLE) ||
destBufferRect == neededRegion.GetBounds(),
"If we're resampling, we need to validate the entire buffer");
if (!createdBuffer && !mHasBuffer) {
return result;
}
if (createdBuffer) {
if (mHasBuffer &&
(mode != SurfaceMode::SURFACE_COMPONENT_ALPHA || mHasBufferOnWhite)) {
mTextureInfo.mDeprecatedTextureHostFlags = DeprecatedTextureHostFlags::COPY_PREVIOUS;
}
mHasBuffer = true;
if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
mHasBufferOnWhite = true;
}
mBufferRect = destBufferRect;
mBufferRotation = nsIntPoint(0,0);
NotifyBufferCreated(contentType, bufferFlags);
}
NS_ASSERTION(canHaveRotation || mBufferRotation == nsIntPoint(0,0),
"Rotation disabled, but we have nonzero rotation?");
nsIntRegion invalidate;
invalidate.Sub(aLayer->GetValidRegion(), destBufferRect);
result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate);
// If we do partial updates, we have to clip drawing to the regionToDraw.
// If we don't clip, background images will be fillrect'd to the region correctly,
// while text or lines will paint outside of the regionToDraw. This becomes apparent
// with concave regions. Right now the scrollbars invalidate a narrow strip of the bar
// although they never cover it. This leads to two draw rects, the narow strip and the actually
// newly exposed area. It would be wise to fix this glitch in any way to have simpler
// clip and draw regions.
result.mClip = DrawRegionClip::DRAW;
result.mMode = mode;
return result;
}
DrawTarget*
ContentClientIncremental::BorrowDrawTargetForPainting(PaintState& aPaintState,
RotatedContentBuffer::DrawIterator* aIter)
{
if (aPaintState.mMode == SurfaceMode::SURFACE_NONE) {
return nullptr;
}
if (aIter) {
if (aIter->mCount++ > 0) {
return nullptr;
}
aIter->mDrawRegion = aPaintState.mRegionToDraw;
}
DrawTarget* result = nullptr;
nsIntRect drawBounds = aPaintState.mRegionToDraw.GetBounds();
MOZ_ASSERT(!mLoanedDrawTarget);
// BeginUpdate is allowed to modify the given region,
// if it wants more to be repainted than we request.
if (aPaintState.mMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
nsIntRegion drawRegionCopy = aPaintState.mRegionToDraw;
RefPtr<DrawTarget> onBlack = GetUpdateSurface(BUFFER_BLACK, drawRegionCopy);
RefPtr<DrawTarget> onWhite = GetUpdateSurface(BUFFER_WHITE, aPaintState.mRegionToDraw);
if (onBlack && onWhite) {
NS_ASSERTION(aPaintState.mRegionToDraw == drawRegionCopy,
"BeginUpdate should always modify the draw region in the same way!");
FillSurface(onBlack, aPaintState.mRegionToDraw, nsIntPoint(drawBounds.x, drawBounds.y), gfxRGBA(0.0, 0.0, 0.0, 1.0));
FillSurface(onWhite, aPaintState.mRegionToDraw, nsIntPoint(drawBounds.x, drawBounds.y), gfxRGBA(1.0, 1.0, 1.0, 1.0));
mLoanedDrawTarget = Factory::CreateDualDrawTarget(onBlack, onWhite);
} else {
mLoanedDrawTarget = nullptr;
}
} else {
mLoanedDrawTarget = GetUpdateSurface(BUFFER_BLACK, aPaintState.mRegionToDraw);
}
if (!mLoanedDrawTarget) {
NS_WARNING("unable to get context for update");
return nullptr;
}
result = mLoanedDrawTarget;
mLoanedTransform = mLoanedDrawTarget->GetTransform();
result->SetTransform(Matrix(mLoanedTransform).
PreTranslate(-drawBounds.x, -drawBounds.y));
if (mContentType == gfxContentType::COLOR_ALPHA) {
gfxUtils::ClipToRegion(result, aPaintState.mRegionToDraw);
nsIntRect bounds = aPaintState.mRegionToDraw.GetBounds();
result->ClearRect(Rect(bounds.x, bounds.y, bounds.width, bounds.height));
}
return result;
}
void
ContentClientIncremental::Updated(const nsIntRegion& aRegionToDraw,
const nsIntRegion& aVisibleRegion,
bool aDidSelfCopy)
{
if (IsSurfaceDescriptorValid(mUpdateDescriptor)) {
mForwarder->UpdateTextureIncremental(this,
TextureIdentifier::Front,
mUpdateDescriptor,
aRegionToDraw,
mBufferRect,
mBufferRotation);
mUpdateDescriptor = SurfaceDescriptor();
}
if (IsSurfaceDescriptorValid(mUpdateDescriptorOnWhite)) {
mForwarder->UpdateTextureIncremental(this,
TextureIdentifier::OnWhiteFront,
mUpdateDescriptorOnWhite,
aRegionToDraw,
mBufferRect,
mBufferRotation);
mUpdateDescriptorOnWhite = SurfaceDescriptor();
}
}
already_AddRefed<DrawTarget>
ContentClientIncremental::GetUpdateSurface(BufferType aType,
const nsIntRegion& aUpdateRegion)
{
nsIntRect rgnSize = aUpdateRegion.GetBounds();
if (!mBufferRect.Contains(rgnSize)) {
NS_ERROR("update outside of image");
return nullptr;
}
SurfaceDescriptor desc;
if (!mForwarder->AllocSurfaceDescriptor(rgnSize.Size().ToIntSize(),
mContentType,
&desc)) {
NS_WARNING("creating SurfaceDescriptor failed!");
Clear();
return nullptr;
}
if (aType == BUFFER_BLACK) {
MOZ_ASSERT(!IsSurfaceDescriptorValid(mUpdateDescriptor));
mUpdateDescriptor = desc;
} else {
MOZ_ASSERT(!IsSurfaceDescriptorValid(mUpdateDescriptorOnWhite));
MOZ_ASSERT(aType == BUFFER_WHITE);
mUpdateDescriptorOnWhite = desc;
}
return GetDrawTargetForDescriptor(desc, gfx::BackendType::COREGRAPHICS);
}
}
}
-83
View File
@@ -397,89 +397,6 @@ public:
}
};
/**
* A single buffered ContentClient that creates temporary buffers which are
* used to update the host-side texture. The ownership of the buffers is
* passed to the host side during the transaction, and we need to create
* new ones each frame.
*/
class ContentClientIncremental : public ContentClientRemote
, public BorrowDrawTarget
{
public:
explicit ContentClientIncremental(CompositableForwarder* aFwd)
: ContentClientRemote(aFwd)
, mContentType(gfxContentType::COLOR_ALPHA)
, mHasBuffer(false)
, mHasBufferOnWhite(false)
{
mTextureInfo.mCompositableType = CompositableType::CONTENT_INC;
}
typedef RotatedContentBuffer::PaintState PaintState;
typedef RotatedContentBuffer::ContentType ContentType;
virtual TextureInfo GetTextureInfo() const override
{
return mTextureInfo;
}
virtual void Clear() override
{
mBufferRect.SetEmpty();
mHasBuffer = false;
mHasBufferOnWhite = false;
}
virtual PaintState BeginPaintBuffer(PaintedLayer* aLayer,
uint32_t aFlags) override;
virtual gfx::DrawTarget* BorrowDrawTargetForPainting(PaintState& aPaintState,
RotatedContentBuffer::DrawIterator* aIter = nullptr) override;
virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) override
{
BorrowDrawTarget::ReturnDrawTarget(aReturned);
}
virtual void Updated(const nsIntRegion& aRegionToDraw,
const nsIntRegion& aVisibleRegion,
bool aDidSelfCopy) override;
virtual void EndPaint(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates = nullptr) override
{
if (IsSurfaceDescriptorValid(mUpdateDescriptor)) {
mForwarder->DestroySharedSurface(&mUpdateDescriptor);
}
if (IsSurfaceDescriptorValid(mUpdateDescriptorOnWhite)) {
mForwarder->DestroySharedSurface(&mUpdateDescriptorOnWhite);
}
ContentClientRemote::EndPaint(aReadbackUpdates);
}
private:
enum BufferType{
BUFFER_BLACK,
BUFFER_WHITE
};
void NotifyBufferCreated(ContentType aType, TextureFlags aFlags);
already_AddRefed<gfx::DrawTarget> GetUpdateSurface(BufferType aType,
const nsIntRegion& aUpdateRegion);
TextureInfo mTextureInfo;
nsIntRect mBufferRect;
nsIntPoint mBufferRotation;
SurfaceDescriptor mUpdateDescriptor;
SurfaceDescriptor mUpdateDescriptorOnWhite;
ContentType mContentType;
bool mHasBuffer;
bool mHasBufferOnWhite;
};
}
}
@@ -183,9 +183,6 @@ CompositableHost::Create(const TextureInfo& aTextureInfo)
case CompositableType::IMAGE_BRIDGE:
NS_ERROR("Cannot create an image bridge compositable this way");
break;
case CompositableType::CONTENT_INC:
result = new ContentHostIncremental(aTextureInfo);
break;
case CompositableType::CONTENT_TILED:
result = new TiledContentHost(aTextureInfo);
break;
-39
View File
@@ -101,45 +101,6 @@ public:
return false;
}
/**
* Update the content host using a surface that only contains the updated
* region.
*
* Takes ownership of aSurface, and is responsible for freeing it.
*
* @param aTextureId Texture to update.
* @param aSurface Surface containing the update area. Its contents are relative
* to aUpdated.TopLeft()
* @param aUpdated Area of the content host to update.
* @param aBufferRect New area covered by the content host.
* @param aBufferRotation New buffer rotation.
*/
virtual void UpdateIncremental(TextureIdentifier aTextureId,
SurfaceDescriptor& aSurface,
const nsIntRegion& aUpdated,
const nsIntRect& aBufferRect,
const nsIntPoint& aBufferRotation)
{
MOZ_ASSERT(false, "should be implemented or not used");
}
/**
* Ensure that a suitable texture host exists in this compsitable.
*
* Only used with ContentHostIncremental.
*
* No SurfaceDescriptor or TextureIdentifier is provider as we
* don't have a single surface for the texture contents, and we
* need to allocate our own one to be updated later.
*/
virtual bool CreatedIncrementalTexture(ISurfaceAllocator* aAllocator,
const TextureInfo& aTextureInfo,
const nsIntRect& aBufferRect)
{
NS_ERROR("should be implemented or not used");
return false;
}
/**
* Returns the front buffer.
*/
-432
View File
@@ -388,429 +388,6 @@ ContentHostDoubleBuffered::UpdateThebes(const ThebesBufferData& aData,
return true;
}
ContentHostIncremental::ContentHostIncremental(const TextureInfo& aTextureInfo)
: ContentHostBase(aTextureInfo)
, mDeAllocator(nullptr)
, mLocked(false)
{
}
ContentHostIncremental::~ContentHostIncremental()
{
}
bool
ContentHostIncremental::CreatedIncrementalTexture(ISurfaceAllocator* aAllocator,
const TextureInfo& aTextureInfo,
const nsIntRect& aBufferRect)
{
mUpdateList.AppendElement(new TextureCreationRequest(aTextureInfo,
aBufferRect));
mDeAllocator = aAllocator;
FlushUpdateQueue();
return true;
}
void
ContentHostIncremental::UpdateIncremental(TextureIdentifier aTextureId,
SurfaceDescriptor& aSurface,
const nsIntRegion& aUpdated,
const nsIntRect& aBufferRect,
const nsIntPoint& aBufferRotation)
{
mUpdateList.AppendElement(new TextureUpdateRequest(mDeAllocator,
aTextureId,
aSurface,
aUpdated,
aBufferRect,
aBufferRotation));
FlushUpdateQueue();
}
void
ContentHostIncremental::Composite(EffectChain& aEffectChain,
float aOpacity,
const gfx::Matrix4x4& aTransform,
const Filter& aFilter,
const Rect& aClipRect,
const nsIntRegion* aVisibleRegion)
{
NS_ASSERTION(aVisibleRegion, "Requires a visible region");
AutoLockCompositableHost lock(this);
if (lock.Failed()) {
return;
}
if (!mSource) {
return;
}
RefPtr<TexturedEffect> effect = CreateTexturedEffect(mSource.get(),
mSourceOnWhite.get(),
aFilter, true);
if (!effect) {
return;
}
aEffectChain.mPrimaryEffect = effect;
nsIntRegion tmpRegion;
const nsIntRegion* renderRegion;
if (PaintWillResample()) {
// If we're resampling, then the texture image will contain exactly the
// entire visible region's bounds, and we should draw it all in one quad
// to avoid unexpected aliasing.
tmpRegion = aVisibleRegion->GetBounds();
renderRegion = &tmpRegion;
} else {
renderRegion = aVisibleRegion;
}
nsIntRegion region(*renderRegion);
nsIntPoint origin = GetOriginOffset();
// translate into TexImage space, buffer origin might not be at texture (0,0)
region.MoveBy(-origin);
// Figure out the intersecting draw region
gfx::IntSize texSize = mSource->GetSize();
nsIntRect textureRect = nsIntRect(0, 0, texSize.width, texSize.height);
textureRect.MoveBy(region.GetBounds().TopLeft());
nsIntRegion subregion;
subregion.And(region, textureRect);
if (subregion.IsEmpty()) {
// Region is empty, nothing to draw
return;
}
nsIntRegion screenRects;
nsIntRegion regionRects;
// Collect texture/screen coordinates for drawing
nsIntRegionRectIterator iter(subregion);
while (const nsIntRect* iterRect = iter.Next()) {
nsIntRect regionRect = *iterRect;
nsIntRect screenRect = regionRect;
screenRect.MoveBy(origin);
screenRects.Or(screenRects, screenRect);
regionRects.Or(regionRects, regionRect);
}
BigImageIterator* bigImgIter = mSource->AsBigImageIterator();
BigImageIterator* iterOnWhite = nullptr;
if (bigImgIter) {
bigImgIter->BeginBigImageIteration();
}
if (mSourceOnWhite) {
iterOnWhite = mSourceOnWhite->AsBigImageIterator();
MOZ_ASSERT(!bigImgIter || bigImgIter->GetTileCount() == iterOnWhite->GetTileCount(),
"Tile count mismatch on component alpha texture");
if (iterOnWhite) {
iterOnWhite->BeginBigImageIteration();
}
}
bool usingTiles = (bigImgIter && bigImgIter->GetTileCount() > 1);
do {
if (iterOnWhite) {
MOZ_ASSERT(iterOnWhite->GetTileRect() == bigImgIter->GetTileRect(),
"component alpha textures should be the same size.");
}
nsIntRect texRect = bigImgIter ? bigImgIter->GetTileRect()
: nsIntRect(0, 0,
texSize.width,
texSize.height);
// Draw texture. If we're using tiles, we do repeating manually, as texture
// repeat would cause each individual tile to repeat instead of the
// compound texture as a whole. This involves drawing at most 4 sections,
// 2 for each axis that has texture repeat.
for (int y = 0; y < (usingTiles ? 2 : 1); y++) {
for (int x = 0; x < (usingTiles ? 2 : 1); x++) {
nsIntRect currentTileRect(texRect);
currentTileRect.MoveBy(x * texSize.width, y * texSize.height);
nsIntRegionRectIterator screenIter(screenRects);
nsIntRegionRectIterator regionIter(regionRects);
const nsIntRect* screenRect;
const nsIntRect* regionRect;
while ((screenRect = screenIter.Next()) &&
(regionRect = regionIter.Next())) {
nsIntRect tileScreenRect(*screenRect);
nsIntRect tileRegionRect(*regionRect);
// When we're using tiles, find the intersection between the tile
// rect and this region rect. Tiling is then handled by the
// outer for-loops and modifying the tile rect.
if (usingTiles) {
tileScreenRect.MoveBy(-origin);
tileScreenRect = tileScreenRect.Intersect(currentTileRect);
tileScreenRect.MoveBy(origin);
if (tileScreenRect.IsEmpty())
continue;
tileRegionRect = regionRect->Intersect(currentTileRect);
tileRegionRect.MoveBy(-currentTileRect.TopLeft());
}
gfx::Rect rect(tileScreenRect.x, tileScreenRect.y,
tileScreenRect.width, tileScreenRect.height);
effect->mTextureCoords = Rect(Float(tileRegionRect.x) / texRect.width,
Float(tileRegionRect.y) / texRect.height,
Float(tileRegionRect.width) / texRect.width,
Float(tileRegionRect.height) / texRect.height);
GetCompositor()->DrawQuad(rect, aClipRect, aEffectChain, aOpacity, aTransform);
if (usingTiles) {
DiagnosticFlags diagnostics = DiagnosticFlags::CONTENT | DiagnosticFlags::BIGIMAGE;
if (iterOnWhite) {
diagnostics |= DiagnosticFlags::COMPONENT_ALPHA;
}
GetCompositor()->DrawDiagnostics(diagnostics, rect, aClipRect,
aTransform, mFlashCounter);
}
}
}
}
if (iterOnWhite) {
iterOnWhite->NextTile();
}
} while (usingTiles && bigImgIter->NextTile());
if (bigImgIter) {
bigImgIter->EndBigImageIteration();
}
if (iterOnWhite) {
iterOnWhite->EndBigImageIteration();
}
DiagnosticFlags diagnostics = DiagnosticFlags::CONTENT;
if (iterOnWhite) {
diagnostics |= DiagnosticFlags::COMPONENT_ALPHA;
}
GetCompositor()->DrawDiagnostics(diagnostics, nsIntRegion(mBufferRect), aClipRect,
aTransform, mFlashCounter);
}
void
ContentHostIncremental::FlushUpdateQueue()
{
// If we're not compositing for some reason (the window being minimized
// is one example), then we never process these updates and it can consume
// huge amounts of memory. Instead we forcibly process the updates (during the
// transaction) if the list gets too long.
static const uint32_t kMaxUpdateCount = 6;
if (mUpdateList.Length() >= kMaxUpdateCount) {
ProcessTextureUpdates();
}
}
void
ContentHostIncremental::ProcessTextureUpdates()
{
for (uint32_t i = 0; i < mUpdateList.Length(); i++) {
mUpdateList[i]->Execute(this);
}
mUpdateList.Clear();
}
void
ContentHostIncremental::TextureCreationRequest::Execute(ContentHostIncremental* aHost)
{
Compositor* compositor = aHost->GetCompositor();
MOZ_ASSERT(compositor);
RefPtr<DataTextureSource> temp =
compositor->CreateDataTextureSource(mTextureInfo.mTextureFlags);
MOZ_ASSERT(temp->AsSourceOGL() &&
temp->AsSourceOGL()->AsTextureImageTextureSource());
RefPtr<TextureImageTextureSourceOGL> newSource =
temp->AsSourceOGL()->AsTextureImageTextureSource();
RefPtr<TextureImageTextureSourceOGL> newSourceOnWhite;
if (mTextureInfo.mTextureFlags & TextureFlags::COMPONENT_ALPHA) {
temp =
compositor->CreateDataTextureSource(mTextureInfo.mTextureFlags);
MOZ_ASSERT(temp->AsSourceOGL() &&
temp->AsSourceOGL()->AsTextureImageTextureSource());
newSourceOnWhite = temp->AsSourceOGL()->AsTextureImageTextureSource();
}
if (mTextureInfo.mDeprecatedTextureHostFlags & DeprecatedTextureHostFlags::COPY_PREVIOUS) {
MOZ_ASSERT(aHost->mSource);
MOZ_ASSERT(aHost->mSource->IsValid());
nsIntRect bufferRect = aHost->mBufferRect;
nsIntPoint bufferRotation = aHost->mBufferRotation;
nsIntRect overlap;
// The buffer looks like:
// ______
// |1 |2 | Where the center point is offset by mBufferRotation from the top-left corner.
// |___|__|
// |3 |4 |
// |___|__|
//
// This is drawn to the screen as:
// ______
// |4 |3 | Where the center point is { width - mBufferRotation.x, height - mBufferRotation.y } from
// |___|__| from the top left corner - rotationPoint.
// |2 |1 |
// |___|__|
//
// The basic idea below is to take all quadrant rectangles from the src and transform them into rectangles
// in the destination. Unfortunately, it seems it is overly complex and could perhaps be simplified.
nsIntRect srcBufferSpaceBottomRight(bufferRotation.x, bufferRotation.y, bufferRect.width - bufferRotation.x, bufferRect.height - bufferRotation.y);
nsIntRect srcBufferSpaceTopRight(bufferRotation.x, 0, bufferRect.width - bufferRotation.x, bufferRotation.y);
nsIntRect srcBufferSpaceTopLeft(0, 0, bufferRotation.x, bufferRotation.y);
nsIntRect srcBufferSpaceBottomLeft(0, bufferRotation.y, bufferRotation.x, bufferRect.height - bufferRotation.y);
overlap.IntersectRect(bufferRect, mBufferRect);
nsIntRect srcRect(overlap), dstRect(overlap);
srcRect.MoveBy(- bufferRect.TopLeft() + bufferRotation);
nsIntRect srcRectDrawTopRight(srcRect);
nsIntRect srcRectDrawTopLeft(srcRect);
nsIntRect srcRectDrawBottomLeft(srcRect);
// transform into the different quadrants
srcRectDrawTopRight .MoveBy(-nsIntPoint(0, bufferRect.height));
srcRectDrawTopLeft .MoveBy(-nsIntPoint(bufferRect.width, bufferRect.height));
srcRectDrawBottomLeft.MoveBy(-nsIntPoint(bufferRect.width, 0));
// Intersect with the quadrant
srcRect = srcRect .Intersect(srcBufferSpaceBottomRight);
srcRectDrawTopRight = srcRectDrawTopRight .Intersect(srcBufferSpaceTopRight);
srcRectDrawTopLeft = srcRectDrawTopLeft .Intersect(srcBufferSpaceTopLeft);
srcRectDrawBottomLeft = srcRectDrawBottomLeft.Intersect(srcBufferSpaceBottomLeft);
dstRect = srcRect;
nsIntRect dstRectDrawTopRight(srcRectDrawTopRight);
nsIntRect dstRectDrawTopLeft(srcRectDrawTopLeft);
nsIntRect dstRectDrawBottomLeft(srcRectDrawBottomLeft);
// transform back to src buffer space
dstRect .MoveBy(-bufferRotation);
dstRectDrawTopRight .MoveBy(-bufferRotation + nsIntPoint(0, bufferRect.height));
dstRectDrawTopLeft .MoveBy(-bufferRotation + nsIntPoint(bufferRect.width, bufferRect.height));
dstRectDrawBottomLeft.MoveBy(-bufferRotation + nsIntPoint(bufferRect.width, 0));
// transform back to draw coordinates
dstRect .MoveBy(bufferRect.TopLeft());
dstRectDrawTopRight .MoveBy(bufferRect.TopLeft());
dstRectDrawTopLeft .MoveBy(bufferRect.TopLeft());
dstRectDrawBottomLeft.MoveBy(bufferRect.TopLeft());
// transform to destBuffer space
dstRect .MoveBy(-mBufferRect.TopLeft());
dstRectDrawTopRight .MoveBy(-mBufferRect.TopLeft());
dstRectDrawTopLeft .MoveBy(-mBufferRect.TopLeft());
dstRectDrawBottomLeft.MoveBy(-mBufferRect.TopLeft());
newSource->EnsureBuffer(mBufferRect.Size(),
ContentForFormat(aHost->mSource->GetFormat()));
aHost->mSource->CopyTo(srcRect, newSource, dstRect);
if (bufferRotation != nsIntPoint(0, 0)) {
// Draw the remaining quadrants. We call BlitTextureImage 3 extra
// times instead of doing a single draw call because supporting that
// with a tiled source is quite tricky.
if (!srcRectDrawTopRight.IsEmpty())
aHost->mSource->CopyTo(srcRectDrawTopRight,
newSource, dstRectDrawTopRight);
if (!srcRectDrawTopLeft.IsEmpty())
aHost->mSource->CopyTo(srcRectDrawTopLeft,
newSource, dstRectDrawTopLeft);
if (!srcRectDrawBottomLeft.IsEmpty())
aHost->mSource->CopyTo(srcRectDrawBottomLeft,
newSource, dstRectDrawBottomLeft);
}
if (newSourceOnWhite) {
newSourceOnWhite->EnsureBuffer(mBufferRect.Size(),
ContentForFormat(aHost->mSourceOnWhite->GetFormat()));
aHost->mSourceOnWhite->CopyTo(srcRect, newSourceOnWhite, dstRect);
if (bufferRotation != nsIntPoint(0, 0)) {
// draw the remaining quadrants
if (!srcRectDrawTopRight.IsEmpty())
aHost->mSourceOnWhite->CopyTo(srcRectDrawTopRight,
newSourceOnWhite, dstRectDrawTopRight);
if (!srcRectDrawTopLeft.IsEmpty())
aHost->mSourceOnWhite->CopyTo(srcRectDrawTopLeft,
newSourceOnWhite, dstRectDrawTopLeft);
if (!srcRectDrawBottomLeft.IsEmpty())
aHost->mSourceOnWhite->CopyTo(srcRectDrawBottomLeft,
newSourceOnWhite, dstRectDrawBottomLeft);
}
}
}
aHost->mSource = newSource;
aHost->mSourceOnWhite = newSourceOnWhite;
aHost->mBufferRect = mBufferRect;
aHost->mBufferRotation = nsIntPoint();
}
nsIntRect
ContentHostIncremental::TextureUpdateRequest::GetQuadrantRectangle(XSide aXSide,
YSide aYSide) const
{
// quadrantTranslation is the amount we translate the top-left
// of the quadrant by to get coordinates relative to the layer
nsIntPoint quadrantTranslation = -mBufferRotation;
quadrantTranslation.x += aXSide == LEFT ? mBufferRect.width : 0;
quadrantTranslation.y += aYSide == TOP ? mBufferRect.height : 0;
return mBufferRect + quadrantTranslation;
}
void
ContentHostIncremental::TextureUpdateRequest::Execute(ContentHostIncremental* aHost)
{
nsIntRect drawBounds = mUpdated.GetBounds();
aHost->mBufferRect = mBufferRect;
aHost->mBufferRotation = mBufferRotation;
// Figure out which quadrant to draw in
int32_t xBoundary = mBufferRect.XMost() - mBufferRotation.x;
int32_t yBoundary = mBufferRect.YMost() - mBufferRotation.y;
XSide sideX = drawBounds.XMost() <= xBoundary ? RIGHT : LEFT;
YSide sideY = drawBounds.YMost() <= yBoundary ? BOTTOM : TOP;
nsIntRect quadrantRect = GetQuadrantRectangle(sideX, sideY);
NS_ASSERTION(quadrantRect.Contains(drawBounds), "Messed up quadrants");
mUpdated.MoveBy(-nsIntPoint(quadrantRect.x, quadrantRect.y));
IntPoint offset = ToIntPoint(-mUpdated.GetBounds().TopLeft());
RefPtr<DataSourceSurface> surf = GetSurfaceForDescriptor(mDescriptor);
if (mTextureId == TextureIdentifier::Front) {
aHost->mSource->Update(surf, &mUpdated, &offset);
} else {
aHost->mSourceOnWhite->Update(surf, &mUpdated, &offset);
}
}
void
ContentHostIncremental::PrintInfo(std::stringstream& aStream, const char* aPrefix)
{
aStream << aPrefix;
aStream << nsPrintfCString("ContentHostIncremental (0x%p)", this).get();
if (PaintWillResample()) {
aStream << " [paint-will-resample]";
}
}
void
ContentHostTexture::PrintInfo(std::stringstream& aStream, const char* aPrefix)
{
@@ -869,15 +446,6 @@ ContentHostTexture::GenEffect(const gfx::Filter& aFilter)
aFilter, true);
}
already_AddRefed<TexturedEffect>
ContentHostIncremental::GenEffect(const gfx::Filter& aFilter)
{
if (!mSource) {
return nullptr;
}
return CreateTexturedEffect(mSource, mSourceOnWhite, aFilter, true);
}
already_AddRefed<gfx::DataSourceSurface>
ContentHostTexture::GetAsSurface()
{
-154
View File
@@ -223,160 +223,6 @@ public:
nsIntRegion* aUpdatedRegionBack);
};
/**
* Maintains a host-side only texture, and gets provided with
* surfaces that only cover the changed pixels during an update.
*
* Takes ownership of the passed in update surfaces, and must
* free them once texture upload is complete.
*
* Delays texture uploads until the next composite to
* avoid blocking the main thread.
*/
class ContentHostIncremental : public ContentHostBase
{
public:
explicit ContentHostIncremental(const TextureInfo& aTextureInfo);
~ContentHostIncremental();
virtual CompositableType GetType() override { return CompositableType::CONTENT_INC; }
virtual LayerRenderState GetRenderState() override { return LayerRenderState(); }
virtual bool CreatedIncrementalTexture(ISurfaceAllocator* aAllocator,
const TextureInfo& aTextureInfo,
const nsIntRect& aBufferRect) override;
virtual void UpdateIncremental(TextureIdentifier aTextureId,
SurfaceDescriptor& aSurface,
const nsIntRegion& aUpdated,
const nsIntRect& aBufferRect,
const nsIntPoint& aBufferRotation) override;
virtual bool UpdateThebes(const ThebesBufferData& aData,
const nsIntRegion& aUpdated,
const nsIntRegion& aOldValidRegionBack,
nsIntRegion* aUpdatedRegionBack) override
{
NS_ERROR("Shouldn't call this");
return false;
}
virtual void Composite(EffectChain& aEffectChain,
float aOpacity,
const gfx::Matrix4x4& aTransform,
const gfx::Filter& aFilter,
const gfx::Rect& aClipRect,
const nsIntRegion* aVisibleRegion = nullptr) override;
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
virtual bool Lock() override {
MOZ_ASSERT(!mLocked);
ProcessTextureUpdates();
mLocked = true;
return true;
}
virtual void Unlock() override {
MOZ_ASSERT(mLocked);
mLocked = false;
}
virtual already_AddRefed<TexturedEffect>
GenEffect(const gfx::Filter& aFilter) override;
private:
void FlushUpdateQueue();
void ProcessTextureUpdates();
class Request
{
public:
Request()
{
MOZ_COUNT_CTOR(ContentHostIncremental::Request);
}
virtual ~Request()
{
MOZ_COUNT_DTOR(ContentHostIncremental::Request);
}
virtual void Execute(ContentHostIncremental *aHost) = 0;
};
class TextureCreationRequest : public Request
{
public:
TextureCreationRequest(const TextureInfo& aTextureInfo,
const nsIntRect& aBufferRect)
: mTextureInfo(aTextureInfo)
, mBufferRect(aBufferRect)
{}
virtual void Execute(ContentHostIncremental *aHost);
private:
TextureInfo mTextureInfo;
nsIntRect mBufferRect;
};
class TextureUpdateRequest : public Request
{
public:
TextureUpdateRequest(ISurfaceAllocator* aDeAllocator,
TextureIdentifier aTextureId,
SurfaceDescriptor& aDescriptor,
const nsIntRegion& aUpdated,
const nsIntRect& aBufferRect,
const nsIntPoint& aBufferRotation)
: mDeAllocator(aDeAllocator)
, mTextureId(aTextureId)
, mDescriptor(aDescriptor)
, mUpdated(aUpdated)
, mBufferRect(aBufferRect)
, mBufferRotation(aBufferRotation)
{}
~TextureUpdateRequest()
{
//TODO: Recycle these?
mDeAllocator->DestroySharedSurface(&mDescriptor);
}
virtual void Execute(ContentHostIncremental *aHost);
private:
enum XSide {
LEFT, RIGHT
};
enum YSide {
TOP, BOTTOM
};
nsIntRect GetQuadrantRectangle(XSide aXSide, YSide aYSide) const;
RefPtr<ISurfaceAllocator> mDeAllocator;
TextureIdentifier mTextureId;
SurfaceDescriptor mDescriptor;
nsIntRegion mUpdated;
nsIntRect mBufferRect;
nsIntPoint mBufferRotation;
};
nsTArray<UniquePtr<Request> > mUpdateList;
// Specific to OGL to avoid exposing methods on TextureSource that only
// have one implementation.
RefPtr<TextureImageTextureSourceOGL> mSource;
RefPtr<TextureImageTextureSourceOGL> mSourceOnWhite;
RefPtr<ISurfaceAllocator> mDeAllocator;
bool mLocked;
};
}
}
@@ -53,7 +53,6 @@ bool
PaintedLayerComposite::SetCompositableHost(CompositableHost* aHost)
{
switch (aHost->GetType()) {
case CompositableType::CONTENT_INC:
case CompositableType::CONTENT_TILED:
case CompositableType::CONTENT_SINGLE:
case CompositableType::CONTENT_DOUBLE:
-25
View File
@@ -55,14 +55,6 @@ public:
*/
virtual void Connect(CompositableClient* aCompositable) = 0;
/**
* Notify the CompositableHost that it should create host-side-only
* texture(s), that we will update incrementally using UpdateTextureIncremental.
*/
virtual void CreatedIncrementalBuffer(CompositableClient* aCompositable,
const TextureInfo& aTextureInfo,
const nsIntRect& aBufferRect) = 0;
/**
* Tell the CompositableHost on the compositor side what TiledLayerBuffer to
* use for the next composition.
@@ -83,23 +75,6 @@ public:
const ThebesBufferData& aThebesBufferData,
const nsIntRegion& aUpdatedRegion) = 0;
/**
* Notify the compositor to update aTextureId using aDescriptor, and take
* ownership of aDescriptor.
*
* aDescriptor only contains the pixels for aUpdatedRegion, and is relative
* to aUpdatedRegion.TopLeft().
*
* aBufferRect/aBufferRotation define the new valid region contained
* within the texture after the update has been applied.
*/
virtual void UpdateTextureIncremental(CompositableClient* aCompositable,
TextureIdentifier aTextureId,
SurfaceDescriptor& aDescriptor,
const nsIntRegion& aUpdatedRegion,
const nsIntRect& aBufferRect,
const nsIntPoint& aBufferRotation) = 0;
/**
* Communicate the picture rect of a YUV image in aLayer to the compositor
*/
@@ -73,20 +73,6 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
EditReplyVector& replyv)
{
switch (aEdit.type()) {
case CompositableOperation::TOpCreatedIncrementalTexture: {
MOZ_LAYERS_LOG(("[ParentSide] Created texture"));
const OpCreatedIncrementalTexture& op = aEdit.get_OpCreatedIncrementalTexture();
CompositableHost* compositable = AsCompositable(op);
bool success =
compositable->CreatedIncrementalTexture(this,
op.textureInfo(),
op.bufferRect());
if (!success) {
return false;
}
break;
}
case CompositableOperation::TOpPaintTextureRegion: {
MOZ_LAYERS_LOG(("[ParentSide] Paint PaintedLayer"));
@@ -116,22 +102,6 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
RenderTraceInvalidateEnd(thebes, "FF00FF");
break;
}
case CompositableOperation::TOpPaintTextureIncremental: {
MOZ_LAYERS_LOG(("[ParentSide] Paint PaintedLayer"));
const OpPaintTextureIncremental& op = aEdit.get_OpPaintTextureIncremental();
CompositableHost* compositable = AsCompositable(op);
SurfaceDescriptor desc = op.image();
compositable->UpdateIncremental(op.textureId(),
desc,
op.updatedRegion(),
op.bufferRect(),
op.bufferRotation());
break;
}
case CompositableOperation::TOpUpdatePictureRect: {
const OpUpdatePictureRect& op = aEdit.get_OpUpdatePictureRect();
CompositableHost* compositable = AsCompositable(op);
-11
View File
@@ -541,17 +541,6 @@ ImageBridgeChild::EndTransaction()
for (nsTArray<EditReply>::size_type i = 0; i < replies.Length(); ++i) {
const EditReply& reply = replies[i];
switch (reply.type()) {
case EditReply::TOpTextureSwap: {
const OpTextureSwap& ots = reply.get_OpTextureSwap();
CompositableClient* compositable =
CompositableClient::FromIPDLActor(ots.compositableChild());
MOZ_ASSERT(compositable);
compositable->SetDescriptorFromReply(ots.textureId(), ots.image());
break;
}
case EditReply::TReturnReleaseFence: {
const ReturnReleaseFence& rep = reply.get_ReturnReleaseFence();
FenceHandle fence = rep.fence();
+1 -17
View File
@@ -13,7 +13,7 @@
#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
#include "mozilla/layers/AsyncTransactionTracker.h" // for AsyncTransactionTrackerHolder
#include "mozilla/layers/CompositableForwarder.h"
#include "mozilla/layers/CompositorTypes.h" // for TextureIdentifier, etc
#include "mozilla/layers/CompositorTypes.h"
#include "mozilla/layers/PImageBridgeChild.h"
#include "nsDebug.h" // for NS_RUNTIMEABORT
#include "nsRegion.h" // for nsIntRegion
@@ -248,16 +248,6 @@ public:
NS_RUNTIMEABORT("should not be called");
}
virtual void UpdateTextureIncremental(CompositableClient* aCompositable,
TextureIdentifier aTextureId,
SurfaceDescriptor& aDescriptor,
const nsIntRegion& aUpdatedRegion,
const nsIntRect& aBufferRect,
const nsIntPoint& aBufferRotation) override
{
NS_RUNTIMEABORT("should not be called");
}
/**
* Communicate the picture rect of a YUV image in aLayer to the compositor
*/
@@ -265,12 +255,6 @@ public:
const nsIntRect& aRect) override;
virtual void CreatedIncrementalBuffer(CompositableClient* aCompositable,
const TextureInfo& aTextureInfo,
const nsIntRect& aBufferRect) override
{
NS_RUNTIMEABORT("should not be called");
}
virtual void UpdateTextureRegion(CompositableClient* aCompositable,
const ThebesBufferData& aThebesBufferData,
const nsIntRegion& aUpdatedRegion) override {
-26
View File
@@ -41,7 +41,6 @@ using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h";
using struct mozilla::layers::FenceHandle from "mozilla/layers/FenceUtils.h";
using struct mozilla::layers::FenceHandleFromChild from "mozilla/layers/FenceUtils.h";
using mozilla::layers::TextureIdentifier from "mozilla/layers/CompositorTypes.h";
using std::string from "string";
namespace mozilla {
@@ -340,27 +339,12 @@ struct OpUseOverlaySource {
OverlaySource overlay;
};
struct OpCreatedIncrementalTexture {
PCompositable compositable;
TextureInfo textureInfo;
nsIntRect bufferRect;
};
struct OpPaintTextureRegion {
PCompositable compositable;
ThebesBufferData bufferData;
nsIntRegion updatedRegion;
};
struct OpPaintTextureIncremental {
PCompositable compositable;
TextureIdentifier textureId;
SurfaceDescriptor image;
nsIntRegion updatedRegion;
nsIntRect bufferRect;
nsIntPoint bufferRotation;
};
struct OpUpdatePictureRect {
PCompositable compositable;
nsIntRect picture;
@@ -439,10 +423,7 @@ struct OpReplyDeliverFence {
union CompositableOperation {
OpUpdatePictureRect;
OpCreatedIncrementalTexture;
OpPaintTextureRegion;
OpPaintTextureIncremental;
OpUseTiledLayerBuffer;
@@ -488,12 +469,6 @@ struct OpContentBufferSwap {
nsIntRegion frontUpdatedRegion;
};
struct OpTextureSwap {
PCompositable compositable;
TextureIdentifier textureId;
SurfaceDescriptor image;
};
struct ReturnReleaseFence {
PCompositable compositable;
PTexture texture;
@@ -504,7 +479,6 @@ struct ReturnReleaseFence {
// only to be used for buffer swapping.
union EditReply {
OpContentBufferSwap;
OpTextureSwap;
ReturnReleaseFence;
};
-30
View File
@@ -352,26 +352,6 @@ ShadowLayerForwarder::UpdateTextureRegion(CompositableClient* aCompositable,
aUpdatedRegion));
}
void
ShadowLayerForwarder::UpdateTextureIncremental(CompositableClient* aCompositable,
TextureIdentifier aTextureId,
SurfaceDescriptor& aDescriptor,
const nsIntRegion& aUpdatedRegion,
const nsIntRect& aBufferRect,
const nsIntPoint& aBufferRotation)
{
CheckSurfaceDescriptor(&aDescriptor);
MOZ_ASSERT(aCompositable);
MOZ_ASSERT(aCompositable->GetIPDLActor());
mTxn->AddNoSwapPaint(OpPaintTextureIncremental(nullptr, aCompositable->GetIPDLActor(),
aTextureId,
aDescriptor,
aUpdatedRegion,
aBufferRect,
aBufferRotation));
}
void
ShadowLayerForwarder::UpdatePictureRect(CompositableClient* aCompositable,
const nsIntRect& aRect)
@@ -815,16 +795,6 @@ ShadowLayerForwarder::Connect(CompositableClient* aCompositable)
aCompositable->InitIPDLActor(actor);
}
void
ShadowLayerForwarder::CreatedIncrementalBuffer(CompositableClient* aCompositable,
const TextureInfo& aTextureInfo,
const nsIntRect& aBufferRect)
{
MOZ_ASSERT(aCompositable);
mTxn->AddNoSwapPaint(OpCreatedIncrementalTexture(nullptr, aCompositable->GetIPDLActor(),
aTextureInfo, aBufferRect));
}
void ShadowLayerForwarder::Attach(CompositableClient* aCompositable,
ShadowableLayer* aLayer)
{
-12
View File
@@ -133,7 +133,6 @@ class Transaction;
class ShadowLayerForwarder : public CompositableForwarder
{
friend class ContentClientIncremental;
friend class ClientLayerManager;
public:
@@ -148,10 +147,6 @@ public:
virtual PTextureChild* CreateTexture(const SurfaceDescriptor& aSharedData,
TextureFlags aFlags) override;
virtual void CreatedIncrementalBuffer(CompositableClient* aCompositable,
const TextureInfo& aTextureInfo,
const nsIntRect& aBufferRect) override;
/**
* Adds an edit in the layers transaction in order to attach
* the corresponding compositable and layer on the compositor side.
@@ -259,13 +254,6 @@ public:
const ThebesBufferData& aThebesBufferData,
const nsIntRegion& aUpdatedRegion) override;
virtual void UpdateTextureIncremental(CompositableClient* aCompositable,
TextureIdentifier aTextureId,
SurfaceDescriptor& aDescriptor,
const nsIntRegion& aUpdatedRegion,
const nsIntRect& aBufferRect,
const nsIntPoint& aBufferRotation) override;
/**
* Communicate the picture rect of an image to the compositor
*/
+3 -7
View File
@@ -1021,8 +1021,6 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
} else {
if (nsGkAtoms::letterFrame==frameType) {
pfd->mIsLetterFrame = true;
} else if (nsGkAtoms::rubyFrame == frameType) {
SyncAnnotationBounds(pfd);
}
if (pfd->mSpan) {
isEmpty = !pfd->mSpan->mHasNonemptyContent && pfd->mFrame->IsSelfEmpty();
@@ -1129,6 +1127,7 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
}
if (nsGkAtoms::rubyFrame == frameType) {
mHasRuby = true;
SyncAnnotationBounds(pfd);
}
}
@@ -2799,17 +2798,15 @@ nsLineLayout::AdvanceAnnotationInlineBounds(PerFrameData* aPFD,
/**
* This function applies the changes of icoord and isize caused by
* justification to annotations of the given frame.
* aPFD must be one of the frames in aContainingSpan.
*/
void
nsLineLayout::ApplyLineJustificationToAnnotations(PerFrameData* aPFD,
PerSpanData* aContainingSpan,
nscoord aDeltaICoord,
nscoord aDeltaISize)
{
PerFrameData* pfd = aPFD->mNextAnnotation;
nscoord containerWidth = ContainerWidthForSpan(aContainingSpan);
while (pfd) {
nscoord containerWidth = pfd->mFrame->GetParent()->GetRect().Width();
AdvanceAnnotationInlineBounds(pfd, containerWidth,
aDeltaICoord, aDeltaISize);
@@ -2878,8 +2875,7 @@ nsLineLayout::ApplyFrameJustification(PerSpanData* aPSD,
// The gaps added to the end of the frame should also be
// excluded from the isize added to the annotation.
ApplyLineJustificationToAnnotations(pfd, aPSD,
deltaICoord, dw - gapsAtEnd);
ApplyLineJustificationToAnnotations(pfd, deltaICoord, dw - gapsAtEnd);
deltaICoord += dw;
pfd->mFrame->SetRect(lineWM, pfd->mBounds, ContainerWidthForSpan(aPSD));
}
-1
View File
@@ -686,7 +686,6 @@ protected:
nscoord aDeltaISize);
void ApplyLineJustificationToAnnotations(PerFrameData* aPFD,
PerSpanData* aContainingSpan,
nscoord aDeltaICoord,
nscoord aDeltaISize);
@@ -0,0 +1,45 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Test for bug 1135361</title>
<style>
body {
font: 48px sans-serif;
}
div {
display: inline-block;
width: 3em;
border: 1px solid silver;
padding: .5em;
}
p {
writing-mode: vertical-rl;
-webkit-writing-mode: vertical-rl;
-ms-writing-mode: tb-rl; /* old syntax. IE */
text-orientation: upright;
-webkit-text-orientation: upright;
height: 4ch;
}
rt {
font-size: 20%; /* ensure ruby is small enough that it won't affect inline spacing */
}
span {
display: inline-block;
height: .5ch; /* shim for fake justification */
}
</style>
</head>
<body>
<div>
<p>
<span></span><ruby><rt>to</rt></ruby>
</p>
</div>
<div>
<p style="text-align:right;">
<ruby><rt>kyo</rt></ruby><span></span>
</p>
</div>
</body>
</html>
@@ -0,0 +1,46 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Test for bug 1135361</title>
<style>
body {
font: 48px sans-serif;
}
div {
display: inline-block;
width: 3em;
border: 1px solid silver;
padding: .5em;
}
p {
writing-mode: vertical-rl;
-webkit-writing-mode: vertical-rl;
-ms-writing-mode: tb-rl; /* old syntax. IE */
text-orientation: upright;
-webkit-text-orientation: upright;
height: 4ch;
text-align: justify;
-moz-text-align-last: justify;
}
rt {
font-size: 20%; /* ensure ruby is small enough that it won't affect inline spacing */
}
.t {
color: transparent;
}
</style>
</head>
<body>
<div>
<p>
<ruby><rt>to</rt></ruby><ruby class="t"><rt>kyo</rt></ruby>
</p>
</div>
<div>
<p>
<ruby class="t"><rt>to</rt></ruby><ruby><rt>kyo</rt></ruby>
</p>
</div>
</body>
</html>
@@ -104,3 +104,4 @@ HTTP(..) == 1127488-align-end-vertical-lr-ltr.html 1127488-align-bottom-left-ref
HTTP(..) == 1127488-align-left-vertical-lr-ltr.html 1127488-align-top-left-ref.html
HTTP(..) == 1127488-align-right-vertical-lr-ltr.html 1127488-align-bottom-left-ref.html
== 1131013-vertical-bidi.html 1131013-vertical-bidi-ref.html
fails-if(B2G) == 1135361-ruby-justify-1.html 1135361-ruby-justify-1-ref.html # bug 1136067
+1 -1
View File
@@ -83,7 +83,7 @@ class Context(KeyedDefaultDict):
# a list to be a problem.
self._all_paths = []
self.config = config
self.executed_time = 0
self.execution_time = 0
self._sandbox = None
KeyedDefaultDict.__init__(self, self._factory)
+8
View File
@@ -243,6 +243,13 @@ AppTrustDomain::IsChainValid(const DERArray& certChain, Time time)
return Success;
}
Result
AppTrustDomain::CheckSignatureDigestAlgorithm(DigestAlgorithm)
{
// TODO: We should restrict signatures to SHA-256 or better.
return Success;
}
Result
AppTrustDomain::CheckRSAPublicKeyModulusSizeInBits(
EndEntityOrCA /*endEntityOrCA*/, unsigned int modulusSizeInBits)
@@ -257,6 +264,7 @@ Result
AppTrustDomain::VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo)
{
// TODO: We should restrict signatures to SHA-256 or better.
return VerifyRSAPKCS1SignedDigestNSS(signedDigest, subjectPublicKeyInfo,
mPinArg);
}
+2
View File
@@ -38,6 +38,8 @@ public:
/*optional*/ const mozilla::pkix::Input* aiaExtension) override;
virtual Result IsChainValid(const mozilla::pkix::DERArray& certChain,
mozilla::pkix::Time time) override;
virtual Result CheckSignatureDigestAlgorithm(
mozilla::pkix::DigestAlgorithm digestAlg) override;
virtual Result CheckRSAPublicKeyModulusSizeInBits(
mozilla::pkix::EndEntityOrCA endEntityOrCA,
unsigned int modulusSizeInBits) override;
@@ -710,6 +710,12 @@ NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray, Time time)
return Success;
}
Result
NSSCertDBTrustDomain::CheckSignatureDigestAlgorithm(DigestAlgorithm)
{
return Success;
}
Result
NSSCertDBTrustDomain::CheckRSAPublicKeyModulusSizeInBits(
EndEntityOrCA /*endEntityOrCA*/, unsigned int modulusSizeInBits)
@@ -70,6 +70,9 @@ public:
/*out*/ mozilla::pkix::TrustLevel& trustLevel)
override;
virtual Result CheckSignatureDigestAlgorithm(
mozilla::pkix::DigestAlgorithm digestAlg) override;
virtual Result CheckRSAPublicKeyModulusSizeInBits(
mozilla::pkix::EndEntityOrCA endEntityOrCA,
unsigned int modulusSizeInBits) override;
@@ -317,3 +317,4 @@ MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE=The server presented a certificate with a
MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA=An X.509 version 1 certificate that is not a trust anchor was used to issue the server's certificate. X.509 version 1 certificates are deprecated and should not be used to sign other certificates.
MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE=The server presented a certificate that is not yet valid.
MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE=A certificate that is not yet valid was used to issue the server's certificate.
MOZILLA_PKIX_ERROR_SIGNATURE_ALGORITHM_MISMATCH=The signature algorithm in the signature field of the certificate does not match the algorithm in its signatureAlgorithm field.
+2
View File
@@ -179,6 +179,8 @@ static const unsigned int FATAL_ERROR_FLAG = 0x800;
MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE) \
MOZILLA_PKIX_MAP(ERROR_UNSUPPORTED_EC_POINT_FORM, 47, \
SEC_ERROR_UNSUPPORTED_EC_POINT_FORM) \
MOZILLA_PKIX_MAP(ERROR_SIGNATURE_ALGORITHM_MISMATCH, 48, \
MOZILLA_PKIX_ERROR_SIGNATURE_ALGORITHM_MISMATCH) \
MOZILLA_PKIX_MAP(FATAL_ERROR_INVALID_ARGS, FATAL_ERROR_FLAG | 1, \
SEC_ERROR_INVALID_ARGS) \
MOZILLA_PKIX_MAP(FATAL_ERROR_INVALID_STATE, FATAL_ERROR_FLAG | 2, \
+1
View File
@@ -81,6 +81,7 @@ enum ErrorCode
MOZILLA_PKIX_ERROR_NO_RFC822NAME_MATCH = ERROR_BASE + 4,
MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE = ERROR_BASE + 5,
MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE = ERROR_BASE + 6,
MOZILLA_PKIX_ERROR_SIGNATURE_ALGORITHM_MISMATCH = ERROR_BASE + 7,
};
void RegisterErrorTable();
+7
View File
@@ -271,6 +271,13 @@ public:
/*optional*/ const Input* stapledOCSPresponse,
/*optional*/ const Input* aiaExtension) = 0;
// Check that the given digest algorithm is acceptable for use in signatures.
//
// Return Success if the algorithm is acceptable,
// Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED if the algorithm is not
// acceptable, or another error code if another error occurred.
virtual Result CheckSignatureDigestAlgorithm(DigestAlgorithm digestAlg) = 0;
// Check that the RSA public key size is acceptable.
//
// Return Success if the key size is acceptable,
-3
View File
@@ -79,9 +79,6 @@ BackCert::Init()
if (rv != Success) {
return rv;
}
// XXX: Ignored. What are we supposed to check? This seems totally redundant
// with Certificate.signatureAlgorithm. Is it important to check that they
// are consistent with each other? It doesn't seem to matter!
rv = der::ExpectTagAndGetValue(tbsCertificate, der::SEQUENCE, signature);
if (rv != Success) {
return rv;
+126 -8
View File
@@ -29,6 +29,99 @@
namespace mozilla { namespace pkix {
// 4.1.1.2 signatureAlgorithm
// 4.1.2.3 signature
Result
CheckSignatureAlgorithm(TrustDomain& trustDomain,
EndEntityOrCA endEntityOrCA,
const der::SignedDataWithSignature& signedData,
Input signatureValue)
{
// 4.1.1.2. signatureAlgorithm
der::PublicKeyAlgorithm publicKeyAlg;
DigestAlgorithm digestAlg;
Reader signatureAlgorithmReader(signedData.algorithm);
Result rv = der::SignatureAlgorithmIdentifierValue(signatureAlgorithmReader,
publicKeyAlg, digestAlg);
if (rv != Success) {
return rv;
}
rv = der::End(signatureAlgorithmReader);
if (rv != Success) {
return rv;
}
// 4.1.2.3. Signature
der::PublicKeyAlgorithm signedPublicKeyAlg;
DigestAlgorithm signedDigestAlg;
Reader signedSignatureAlgorithmReader(signatureValue);
rv = der::SignatureAlgorithmIdentifierValue(signedSignatureAlgorithmReader,
signedPublicKeyAlg,
signedDigestAlg);
if (rv != Success) {
return rv;
}
rv = der::End(signedSignatureAlgorithmReader);
if (rv != Success) {
return rv;
}
// "This field MUST contain the same algorithm identifier as the
// signatureAlgorithm field in the sequence Certificate." However, it may
// be encoded differently. In particular, one of the fields may have a NULL
// parameter while the other one may omit the parameter field altogether, and
// these are considered equivalent. Some certificates generation software
// actually generates certificates like that, so we compare the parsed values
// instead of comparing the encoded values byte-for-byte.
//
// Along the same lines, we accept two different OIDs for RSA-with-SHA1, and
// we consider those OIDs to be equivalent here.
if (publicKeyAlg != signedPublicKeyAlg || digestAlg != signedDigestAlg) {
return Result::ERROR_SIGNATURE_ALGORITHM_MISMATCH;
}
// During the time of the deprecation of SHA-1 and the deprecation of RSA
// keys of less than 2048 bits, we will encounter many certs signed using
// SHA-1 and/or too-small RSA keys. With this in mind, we ask the trust
// domain early on if it knows it will reject the signature purely based on
// the digest algorithm and/or the RSA key size (if an RSA signature). This
// is a good optimization because it completely avoids calling
// trustDomain.FindIssuers (which may be slow) for such rejected certs, and
// more generally it short-circuits any path building with them (which, of
// course, is even slower).
rv = trustDomain.CheckSignatureDigestAlgorithm(digestAlg);
if (rv != Success) {
return rv;
}
switch (publicKeyAlg) {
case der::PublicKeyAlgorithm::RSA_PKCS1:
{
// The RSA computation may give a result that requires fewer bytes to
// encode than the public key (since it is modular arithmetic). However,
// the last step of generating a PKCS#1.5 signature is the I2OSP
// procedure, which pads any such shorter result with zeros so that it
// is exactly the same length as the public key.
unsigned int signatureSizeInBits = signedData.signature.GetLength() * 8u;
return trustDomain.CheckRSAPublicKeyModulusSizeInBits(
endEntityOrCA, signatureSizeInBits);
}
case der::PublicKeyAlgorithm::ECDSA:
// In theory, we could implement a similar early-pruning optimization for
// ECDSA curves. However, since there has been no similar deprecation for
// for any curve that we support, the chances of us encountering a curve
// during path building is too low to be worth bothering with.
break;
MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
}
return Success;
}
// 4.1.2.5 Validity
Result
@@ -735,21 +828,46 @@ CheckIssuerIndependentProperties(TrustDomain& trustDomain,
const EndEntityOrCA endEntityOrCA = cert.endEntityOrCA;
// Check the cert's trust first, because we want to minimize the amount of
// processing we do on a distrusted cert, in case it is trying to exploit
// some bug in our processing.
rv = trustDomain.GetCertTrust(endEntityOrCA, requiredPolicy, cert.GetDER(),
trustLevel);
if (rv != Success) {
return rv;
}
if (trustLevel == TrustLevel::ActivelyDistrusted) {
return Result::ERROR_UNTRUSTED_CERT;
}
if (trustLevel != TrustLevel::TrustAnchor &&
trustLevel != TrustLevel::InheritsTrust) {
// The TrustDomain returned a trust level that we weren't expecting.
return Result::FATAL_ERROR_INVALID_STATE;
if (trustLevel == TrustLevel::TrustAnchor &&
endEntityOrCA == EndEntityOrCA::MustBeEndEntity &&
requiredEKUIfPresent == KeyPurposeId::id_kp_OCSPSigning) {
// OCSP signer certificates can never be trust anchors, especially
// since we don't support designated OCSP responders. All of the checks
// below that are dependent on trustLevel rely on this overriding of the
// trust level for OCSP signers.
trustLevel = TrustLevel::InheritsTrust;
}
// Check the SPKI first, because it is one of the most selective properties
switch (trustLevel) {
case TrustLevel::InheritsTrust:
rv = CheckSignatureAlgorithm(trustDomain, endEntityOrCA,
cert.GetSignedData(), cert.GetSignature());
if (rv != Success) {
return rv;
}
break;
case TrustLevel::TrustAnchor:
// We don't even bother checking signatureAlgorithm or signature for
// syntactic validity for trust anchors, because we don't use those
// fields for anything, and because the trust anchor might be signed
// with a signature algorithm we don't actually support.
break;
case TrustLevel::ActivelyDistrusted:
return Result::ERROR_UNTRUSTED_CERT;
}
// Check the SPKI early, because it is one of the most selective properties
// of the certificate due to SHA-1 deprecation and the deprecation of
// certificates with keys weaker than RSA 2048.
Reader spki(cert.GetSubjectPublicKeyInfo());
+7 -9
View File
@@ -111,6 +111,13 @@ SignatureAlgorithmIdentifierValue(Reader& input,
/*out*/ PublicKeyAlgorithm& publicKeyAlgorithm,
/*out*/ DigestAlgorithm& digestAlgorithm)
{
// RFC 5758 Section 3.2 (ECDSA with SHA-2), and RFC 3279 Section 2.2.3
// (ECDSA with SHA-1) say that parameters must be omitted.
//
// RFC 4055 Section 5 and RFC 3279 Section 2.2.1 both say that parameters for
// RSA must be encoded as NULL; we relax that requirement by allowing the
// NULL to be omitted, to match all the other signature algorithms we support
// and for compatibility.
Reader algorithmID;
Result rv = AlgorithmIdentifierValue(input, algorithmID);
if (rv != Success) {
@@ -166,15 +173,6 @@ SignatureAlgorithmIdentifierValue(Reader& input,
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01
};
// RFC 5758 Section 3.1 (DSA with SHA-2), RFC 3279 Section 2.2.2 (DSA with
// SHA-1), RFC 5758 Section 3.2 (ECDSA with SHA-2), and RFC 3279
// Section 2.2.3 (ECDSA with SHA-1) all say that parameters must be omitted.
//
// RFC 4055 Section 5 and RFC 3279 Section 2.2.1 both say that parameters for
// RSA must be encoded as NULL; we relax that requirement by allowing the
// NULL to be omitted, to match all the other signature algorithms we support
// and for compatibility.
// Matching is attempted based on a rough estimate of the commonality of the
// algorithm, to minimize the number of MatchRest calls.
if (algorithmID.MatchRest(sha256WithRSAEncryption)) {
+3
View File
@@ -194,6 +194,9 @@ RegisterErrorTable()
{ "MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE",
"A certificate that is not yet valid was used to issue the server's "
"certificate." },
{ "MOZILLA_PKIX_ERROR_SIGNATURE_ALGORITHM_MISMATCH",
"The signature algorithm in the signature field of the certificate does "
"not match the algorithm in its signatureAlgorithm field." },
};
// Note that these error strings are not localizable.
// When these strings change, update the localization information too.
+4 -2
View File
@@ -53,16 +53,18 @@ public:
Result Init();
const Input GetDER() const { return der; }
der::Version GetVersion() const { return version; }
const der::SignedDataWithSignature& GetSignedData() const {
return signedData;
}
der::Version GetVersion() const { return version; }
const Input GetSerialNumber() const { return serialNumber; }
const Input GetSignature() const { return signature; }
const Input GetIssuer() const { return issuer; }
// XXX: "validity" is a horrible name for the structure that holds
// notBefore & notAfter, but that is the name used in RFC 5280 and we use the
// RFC 5280 names for everything.
const Input GetValidity() const { return validity; }
const Input GetSerialNumber() const { return serialNumber; }
const Input GetSubject() const { return subject; }
const Input GetSubjectPublicKeyInfo() const
{
+1
View File
@@ -9,6 +9,7 @@ SOURCES += [
'pkixcert_extension_tests.cpp',
'pkixcert_signature_algorithm_tests.cpp',
'pkixcheck_CheckKeyUsage_tests.cpp',
'pkixcheck_CheckSignatureAlgorithm_tests.cpp',
'pkixcheck_CheckValidity_tests.cpp',
# The naming conventions are described in ./README.txt.
+4 -152
View File
@@ -36,9 +36,7 @@
#pragma warning(pop)
#endif
#include "pkix/pkix.h"
#include "pkixgtest.h"
#include "pkixtestutil.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::test;
@@ -80,7 +78,7 @@ CreateCert(const char* issuerCN, // null means "empty name"
return certDER;
}
class TestTrustDomain final : public TrustDomain
class TestTrustDomain final : public DefaultCryptoTrustDomain
{
public:
// The "cert chain tail" is a longish chain of certificates that is used by
@@ -153,36 +151,6 @@ private:
return Success;
}
Result DigestBuf(Input input, DigestAlgorithm digestAlg,
/*out*/ uint8_t* digestBuf, size_t digestLen) override
{
return TestDigestBuf(input, digestAlg, digestBuf, digestLen);
}
Result CheckRSAPublicKeyModulusSizeInBits(EndEntityOrCA, unsigned int)
override
{
return Success;
}
Result VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyRSAPKCS1SignedDigest(signedDigest, subjectPublicKeyInfo);
}
Result CheckECDSACurveIsAcceptable(EndEntityOrCA, NamedCurve) override
{
return Success;
}
Result VerifyECDSASignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyECDSASignedDigest(signedDigest, subjectPublicKeyInfo);
}
std::map<ByteString, ByteString> subjectDERToCertDER;
ByteString leafCACertDER;
ByteString rootCACertDER;
@@ -276,7 +244,7 @@ TEST_F(pkixbuild, BeyondMaxAcceptableCertChainLength)
// is treated as a trust anchor and is assumed to have issued all certificates
// (i.e. FindIssuer always attempts to build the next step in the chain with
// it).
class ExpiredCertTrustDomain final : public TrustDomain
class ExpiredCertTrustDomain final : public DefaultCryptoTrustDomain
{
public:
explicit ExpiredCertTrustDomain(ByteString rootDER)
@@ -315,48 +283,11 @@ public:
return checker.Check(rootCert, nullptr, keepGoing);
}
Result CheckRevocation(EndEntityOrCA, const CertID&, Time,
/*optional*/ const Input*,
/*optional*/ const Input*) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result IsChainValid(const DERArray&, Time) override
{
return Success;
}
Result DigestBuf(Input input, DigestAlgorithm digestAlg,
/*out*/ uint8_t* digestBuf, size_t digestLen) override
{
return TestDigestBuf(input, digestAlg, digestBuf, digestLen);
}
Result CheckRSAPublicKeyModulusSizeInBits(EndEntityOrCA, unsigned int)
override
{
return Success;
}
Result VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyRSAPKCS1SignedDigest(signedDigest, subjectPublicKeyInfo);
}
Result CheckECDSACurveIsAcceptable(EndEntityOrCA, NamedCurve) override
{
return Success;
}
Result VerifyECDSASignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyECDSASignedDigest(signedDigest, subjectPublicKeyInfo);
}
private:
ByteString rootDER;
};
@@ -394,7 +325,7 @@ TEST_F(pkixbuild, NoRevocationCheckingForExpiredCert)
nullptr));
}
class DSSTrustDomain final : public TrustDomain
class DSSTrustDomain final : public EverythingFailsByDefaultTrustDomain
{
public:
Result GetCertTrust(EndEntityOrCA, const CertPolicyId&,
@@ -403,56 +334,6 @@ public:
trustLevel = TrustLevel::TrustAnchor;
return Success;
}
Result FindIssuer(Input, IssuerChecker&, Time) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result CheckRevocation(EndEntityOrCA, const CertID&, Time,
/*optional*/ const Input*,
/*optional*/ const Input*) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result IsChainValid(const DERArray&, Time) override
{
return Success;
}
Result DigestBuf(Input, DigestAlgorithm, /*out*/uint8_t*, size_t) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result CheckRSAPublicKeyModulusSizeInBits(EndEntityOrCA, unsigned int)
override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result VerifyRSAPKCS1SignedDigest(const SignedDigest&, Input) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result CheckECDSACurveIsAcceptable(EndEntityOrCA, NamedCurve) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result VerifyECDSASignedDigest(const SignedDigest&, Input) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
};
class pkixbuild_DSS : public ::testing::Test { };
@@ -492,7 +373,7 @@ TEST_F(pkixbuild_DSS, DSSEndEntityKeyNotAccepted)
nullptr/*stapledOCSPResponse*/));
}
class IssuerNameCheckTrustDomain final : public TrustDomain
class IssuerNameCheckTrustDomain final : public DefaultCryptoTrustDomain
{
public:
IssuerNameCheckTrustDomain(const ByteString& issuer, bool expectedKeepGoing)
@@ -534,35 +415,6 @@ public:
return Success;
}
Result DigestBuf(Input input, DigestAlgorithm digestAlg,
/*out*/ uint8_t* digestBuf, size_t digestLen) override
{
return TestDigestBuf(input, digestAlg, digestBuf, digestLen);
}
Result CheckRSAPublicKeyModulusSizeInBits(EndEntityOrCA, unsigned int)
override
{
return Success;
}
Result VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyRSAPKCS1SignedDigest(signedDigest, subjectPublicKeyInfo);
}
Result CheckECDSACurveIsAcceptable(EndEntityOrCA, NamedCurve) override
{
return Success;
}
Result VerifyECDSASignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyECDSASignedDigest(signedDigest, subjectPublicKeyInfo);
}
private:
const ByteString issuer;
const bool expectedKeepGoing;
@@ -22,10 +22,8 @@
* limitations under the License.
*/
#include "pkix/pkix.h"
#include "pkixder.h"
#include "pkixgtest.h"
#include "pkixtestutil.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::test;
@@ -60,7 +58,7 @@ CreateCertWithOneExtension(const char* subjectStr, const ByteString& extension)
return CreateCertWithExtensions(subjectStr, extensions);
}
class TrustEverythingTrustDomain final : public TrustDomain
class TrustEverythingTrustDomain final : public DefaultCryptoTrustDomain
{
private:
Result GetCertTrust(EndEntityOrCA, const CertPolicyId&, Input,
@@ -70,13 +68,6 @@ private:
return Success;
}
Result FindIssuer(Input /*encodedIssuerName*/, IssuerChecker& /*checker*/,
Time /*time*/) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result CheckRevocation(EndEntityOrCA, const CertID&, Time,
/*optional*/ const Input*, /*optional*/ const Input*)
override
@@ -88,36 +79,6 @@ private:
{
return Success;
}
Result DigestBuf(Input input, DigestAlgorithm digestAlg,
/*out*/ uint8_t* digestBuf, size_t digestLen) override
{
return TestDigestBuf(input, digestAlg, digestBuf, digestLen);
}
Result CheckRSAPublicKeyModulusSizeInBits(EndEntityOrCA, unsigned int)
override
{
return Success;
}
Result VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyRSAPKCS1SignedDigest(signedDigest, subjectPublicKeyInfo);
}
Result CheckECDSACurveIsAcceptable(EndEntityOrCA, NamedCurve) override
{
return Success;
}
Result VerifyECDSASignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyECDSASignedDigest(signedDigest, subjectPublicKeyInfo);
}
};
// python DottedOIDToCode.py --tlv unknownExtensionOID 1.3.6.1.4.1.13769.666.666.666.1.500.9.3
@@ -3,9 +3,7 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
#include "pkix/pkix.h"
#include "pkixgtest.h"
#include "pkixtestutil.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::test;
@@ -45,7 +43,7 @@ CreateCert(const char* issuerCN,
return certDER;
}
class AlgorithmTestsTrustDomain final : public TrustDomain
class AlgorithmTestsTrustDomain final : public DefaultCryptoTrustDomain
{
public:
AlgorithmTestsTrustDomain(const ByteString& rootDER,
@@ -103,35 +101,6 @@ private:
return Success;
}
Result DigestBuf(Input input, DigestAlgorithm digestAlg,
/*out*/ uint8_t* digestBuf, size_t digestLen) override
{
return TestDigestBuf(input, digestAlg, digestBuf, digestLen);
}
Result CheckRSAPublicKeyModulusSizeInBits(EndEntityOrCA, unsigned int)
override
{
return Success;
}
Result VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyRSAPKCS1SignedDigest(signedDigest, subjectPublicKeyInfo);
}
Result CheckECDSACurveIsAcceptable(EndEntityOrCA, NamedCurve) override
{
return Success;
}
Result VerifyECDSASignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyECDSASignedDigest(signedDigest, subjectPublicKeyInfo);
}
ByteString rootDER;
ByteString rootSubjectDER;
ByteString intDER;
@@ -23,8 +23,6 @@
*/
#include "pkixgtest.h"
#include "pkix/pkixtypes.h"
#include "pkixtestutil.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::test;
@@ -0,0 +1,358 @@
/* -*- 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 code is made available to you under your choice of the following sets
* of licensing terms:
*/
/* 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/.
*/
/* Copyright 2015 Mozilla Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "pkixder.h"
#include "pkixgtest.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::test;
namespace mozilla { namespace pkix {
extern Result CheckSignatureAlgorithm(
TrustDomain& trustDomain, EndEntityOrCA endEntityOrCA,
const der::SignedDataWithSignature& signedData,
Input signatureValue);
} } // namespace mozilla::pkix
struct CheckSignatureAlgorithmTestParams
{
ByteString signatureAlgorithmValue;
ByteString signatureValue;
unsigned int signatureLengthInBytes;
Result expectedResult;
};
#define BS(s) ByteString(s, MOZILLA_PKIX_ARRAY_LENGTH(s))
// python DottedOIDToCode.py --tlv sha256WithRSAEncryption 1.2.840.113549.1.1.11
static const uint8_t tlv_sha256WithRSAEncryption[] = {
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b
};
// Same as tlv_sha256WithRSAEncryption, except one without the "0x0b" and with
// the DER length decreased accordingly.
static const uint8_t tlv_sha256WithRSAEncryption_truncated[] = {
0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01
};
// python DottedOIDToCode.py --tlv sha-1WithRSAEncryption 1.2.840.113549.1.1.5
static const uint8_t tlv_sha_1WithRSAEncryption[] = {
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05
};
// python DottedOIDToCode.py --tlv sha1WithRSASignature 1.3.14.3.2.29
static const uint8_t tlv_sha1WithRSASignature[] = {
0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d
};
// python DottedOIDToCode.py --tlv md5WithRSAEncryption 1.2.840.113549.1.1.4
static const uint8_t tlv_md5WithRSAEncryption[] = {
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04
};
static const CheckSignatureAlgorithmTestParams
CHECKSIGNATUREALGORITHM_TEST_PARAMS[] =
{
{ // Both algorithm IDs are empty
ByteString(),
ByteString(),
2048 / 8,
Result::ERROR_BAD_DER,
},
{ // signatureAlgorithm is empty, signature is supported.
ByteString(),
BS(tlv_sha256WithRSAEncryption),
2048 / 8,
Result::ERROR_BAD_DER,
},
{ // signatureAlgorithm is supported, signature is empty.
BS(tlv_sha256WithRSAEncryption),
ByteString(),
2048 / 8,
Result::ERROR_BAD_DER,
},
{ // Algorithms match, both are supported.
BS(tlv_sha256WithRSAEncryption),
BS(tlv_sha256WithRSAEncryption),
2048 / 8,
Success
},
{ // Algorithms do not match because signatureAlgorithm is truncated.
BS(tlv_sha256WithRSAEncryption_truncated),
BS(tlv_sha256WithRSAEncryption),
2048 / 8,
Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
},
{ // Algorithms do not match because signature is truncated.
BS(tlv_sha256WithRSAEncryption),
BS(tlv_sha256WithRSAEncryption_truncated),
2048 / 8,
Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
},
{ // Algorithms do not match, both are supported.
BS(tlv_sha_1WithRSAEncryption),
BS(tlv_sha256WithRSAEncryption),
2048 / 8,
Result::ERROR_SIGNATURE_ALGORITHM_MISMATCH,
},
{ // Algorithms do not match, both are supported.
BS(tlv_sha256WithRSAEncryption),
BS(tlv_sha_1WithRSAEncryption),
2048 / 8,
Result::ERROR_SIGNATURE_ALGORITHM_MISMATCH,
},
{ // Algorithms match, both are unsupported.
BS(tlv_md5WithRSAEncryption),
BS(tlv_md5WithRSAEncryption),
2048 / 8,
Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
},
{ // signatureAlgorithm is unsupported, signature is supported.
BS(tlv_md5WithRSAEncryption),
BS(tlv_sha256WithRSAEncryption),
2048 / 8,
Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
},
{ // signatureAlgorithm is supported, signature is unsupported.
BS(tlv_sha256WithRSAEncryption),
BS(tlv_md5WithRSAEncryption),
2048 / 8,
Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
},
{ // Both have the optional NULL parameter.
BS(tlv_sha256WithRSAEncryption) + TLV(der::NULLTag, ByteString()),
BS(tlv_sha256WithRSAEncryption) + TLV(der::NULLTag, ByteString()),
2048 / 8,
Success
},
{ // signatureAlgorithm has the optional NULL parameter, signature doesn't.
BS(tlv_sha256WithRSAEncryption) + TLV(der::NULLTag, ByteString()),
BS(tlv_sha256WithRSAEncryption),
2048 / 8,
Success
},
{ // signatureAlgorithm does not have the optional NULL parameter, signature
// does.
BS(tlv_sha256WithRSAEncryption),
BS(tlv_sha256WithRSAEncryption) + TLV(der::NULLTag, ByteString()),
2048 / 8,
Success
},
{ // The different OIDs for RSA-with-SHA1 we support are semantically
// equivalent.
BS(tlv_sha1WithRSASignature),
BS(tlv_sha_1WithRSAEncryption),
2048 / 8,
Success,
},
{ // The different OIDs for RSA-with-SHA1 we support are semantically
// equivalent (opposite order).
BS(tlv_sha_1WithRSAEncryption),
BS(tlv_sha1WithRSASignature),
2048 / 8,
Success,
},
{ // Algorithms match, both are supported, key size is not a multile of 128
// bits. This test verifies that we're not wrongly rounding up the
// signature size like we did in the original patch for bug 1131767.
BS(tlv_sha256WithRSAEncryption),
BS(tlv_sha256WithRSAEncryption),
(2048 / 8) - 1,
Success
},
};
class pkixcheck_CheckSignatureAlgorithm
: public ::testing::Test
, public ::testing::WithParamInterface<CheckSignatureAlgorithmTestParams>
{
};
class pkixcheck_CheckSignatureAlgorithm_TrustDomain final
: public EverythingFailsByDefaultTrustDomain
{
public:
explicit pkixcheck_CheckSignatureAlgorithm_TrustDomain(
unsigned int publicKeySizeInBits)
: publicKeySizeInBits(publicKeySizeInBits)
, checkedDigestAlgorithm(false)
, checkedModulusSizeInBits(false)
{
}
Result CheckSignatureDigestAlgorithm(DigestAlgorithm) override
{
checkedDigestAlgorithm = true;
return Success;
}
Result CheckRSAPublicKeyModulusSizeInBits(EndEntityOrCA endEntityOrCA,
unsigned int modulusSizeInBits)
override
{
EXPECT_EQ(EndEntityOrCA::MustBeEndEntity, endEntityOrCA);
EXPECT_EQ(publicKeySizeInBits, modulusSizeInBits);
checkedModulusSizeInBits = true;
return Success;
}
const unsigned int publicKeySizeInBits;
bool checkedDigestAlgorithm;
bool checkedModulusSizeInBits;
};
TEST_P(pkixcheck_CheckSignatureAlgorithm, CheckSignatureAlgorithm)
{
const CheckSignatureAlgorithmTestParams& params(GetParam());
Input signatureValueInput;
ASSERT_EQ(Success,
signatureValueInput.Init(params.signatureValue.data(),
params.signatureValue.length()));
pkixcheck_CheckSignatureAlgorithm_TrustDomain
trustDomain(params.signatureLengthInBytes * 8);
der::SignedDataWithSignature signedData;
ASSERT_EQ(Success,
signedData.algorithm.Init(params.signatureAlgorithmValue.data(),
params.signatureAlgorithmValue.length()));
ByteString dummySignature(params.signatureLengthInBytes, 0xDE);
ASSERT_EQ(Success,
signedData.signature.Init(dummySignature.data(),
dummySignature.length()));
ASSERT_EQ(params.expectedResult,
CheckSignatureAlgorithm(trustDomain, EndEntityOrCA::MustBeEndEntity,
signedData, signatureValueInput));
ASSERT_EQ(params.expectedResult == Success,
trustDomain.checkedDigestAlgorithm);
ASSERT_EQ(params.expectedResult == Success,
trustDomain.checkedModulusSizeInBits);
}
INSTANTIATE_TEST_CASE_P(
pkixcheck_CheckSignatureAlgorithm, pkixcheck_CheckSignatureAlgorithm,
testing::ValuesIn(CHECKSIGNATUREALGORITHM_TEST_PARAMS));
class pkixcheck_CheckSignatureAlgorithm_BuildCertChain_TrustDomain
: public DefaultCryptoTrustDomain
{
public:
explicit pkixcheck_CheckSignatureAlgorithm_BuildCertChain_TrustDomain(
const ByteString& issuer)
: issuer(issuer)
{
}
Result GetCertTrust(EndEntityOrCA, const CertPolicyId&,
Input cert, /*out*/ TrustLevel& trustLevel) override
{
trustLevel = InputEqualsByteString(cert, issuer)
? TrustLevel::TrustAnchor
: TrustLevel::InheritsTrust;
return Success;
}
Result FindIssuer(Input, IssuerChecker& checker, Time) override
{
EXPECT_FALSE(ENCODING_FAILED(issuer));
Input issuerInput;
EXPECT_EQ(Success, issuerInput.Init(issuer.data(), issuer.length()));
bool keepGoing;
EXPECT_EQ(Success, checker.Check(issuerInput, nullptr, keepGoing));
EXPECT_FALSE(keepGoing);
return Success;
}
Result CheckRevocation(EndEntityOrCA, const CertID&, Time,
/*optional*/ const Input*,
/*optional*/ const Input*) override
{
return Success;
}
Result IsChainValid(const DERArray&, Time) override
{
return Success;
}
ByteString issuer;
};
// Test that CheckSignatureAlgorithm actually gets called at some point when
// BuildCertChain is called.
TEST_F(pkixcheck_CheckSignatureAlgorithm, BuildCertChain)
{
ScopedTestKeyPair keyPair(CloneReusedKeyPair());
ASSERT_TRUE(keyPair);
ByteString issuerExtensions[2];
issuerExtensions[0] = CreateEncodedBasicConstraints(true, nullptr,
Critical::No);
ASSERT_FALSE(ENCODING_FAILED(issuerExtensions[0]));
ByteString issuer(CreateEncodedCertificate(3,
sha256WithRSAEncryption,
CreateEncodedSerialNumber(1),
CNToDERName("issuer"),
oneDayBeforeNow, oneDayAfterNow,
CNToDERName("issuer"),
*keyPair,
issuerExtensions,
*keyPair,
sha256WithRSAEncryption));
ASSERT_FALSE(ENCODING_FAILED(issuer));
ByteString subject(CreateEncodedCertificate(3,
TLV(der::SEQUENCE,
BS(tlv_sha_1WithRSAEncryption)),
CreateEncodedSerialNumber(2),
CNToDERName("issuer"),
oneDayBeforeNow, oneDayAfterNow,
CNToDERName("subject"),
*keyPair,
nullptr,
*keyPair,
sha256WithRSAEncryption));
ASSERT_FALSE(ENCODING_FAILED(subject));
Input subjectInput;
ASSERT_EQ(Success, subjectInput.Init(subject.data(), subject.length()));
pkixcheck_CheckSignatureAlgorithm_BuildCertChain_TrustDomain
trustDomain(issuer);
Result rv = BuildCertChain(trustDomain, subjectInput, Now(),
EndEntityOrCA::MustBeEndEntity,
KeyUsage::noParticularKeyUsageRequired,
KeyPurposeId::anyExtendedKeyUsage,
CertPolicyId::anyPolicy,
nullptr);
ASSERT_EQ(Result::ERROR_SIGNATURE_ALGORITHM_MISMATCH, rv);
}
@@ -23,8 +23,6 @@
*/
#include "pkixgtest.h"
#include "pkix/pkixtypes.h"
#include "pkixtestutil.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::test;
@@ -23,12 +23,11 @@
*/
#include <limits>
#include <stdint.h>
#include <vector>
#include "pkixgtest.h"
#include "pkixder.h"
#include "pkixtestutil.h"
#include "stdint.h"
#include "pkixgtest.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::der;
+118 -1
View File
@@ -56,7 +56,8 @@
#pragma warning(pop)
#endif
#include "pkix/Result.h"
#include "pkix/pkix.h"
#include "pkixtestutil.h"
// PrintTo must be in the same namespace as the type we're overloading it for.
namespace mozilla { namespace pkix {
@@ -82,6 +83,122 @@ extern const std::time_t now;
extern const std::time_t oneDayBeforeNow;
extern const std::time_t oneDayAfterNow;
class EverythingFailsByDefaultTrustDomain : public TrustDomain
{
public:
Result GetCertTrust(EndEntityOrCA, const CertPolicyId&,
Input, /*out*/ TrustLevel&) override
{
ADD_FAILURE();
return NotReached("GetCertTrust should not be called",
Result::FATAL_ERROR_LIBRARY_FAILURE);
}
Result FindIssuer(Input, IssuerChecker&, Time) override
{
ADD_FAILURE();
return NotReached("FindIssuer should not be called",
Result::FATAL_ERROR_LIBRARY_FAILURE);
}
Result CheckRevocation(EndEntityOrCA, const CertID&, Time,
/*optional*/ const Input*,
/*optional*/ const Input*) override
{
ADD_FAILURE();
return NotReached("CheckRevocation should not be called",
Result::FATAL_ERROR_LIBRARY_FAILURE);
}
Result IsChainValid(const DERArray&, Time) override
{
ADD_FAILURE();
return NotReached("IsChainValid should not be called",
Result::FATAL_ERROR_LIBRARY_FAILURE);
}
Result DigestBuf(Input, DigestAlgorithm, /*out*/ uint8_t*, size_t) override
{
ADD_FAILURE();
return NotReached("DigestBuf should not be called",
Result::FATAL_ERROR_LIBRARY_FAILURE);
}
Result CheckSignatureDigestAlgorithm(DigestAlgorithm) override
{
ADD_FAILURE();
return NotReached("CheckSignatureDigestAlgorithm should not be called",
Result::FATAL_ERROR_LIBRARY_FAILURE);
}
Result CheckECDSACurveIsAcceptable(EndEntityOrCA, NamedCurve) override
{
ADD_FAILURE();
return NotReached("CheckECDSACurveIsAcceptable should not be called",
Result::FATAL_ERROR_LIBRARY_FAILURE);
}
Result VerifyECDSASignedDigest(const SignedDigest&, Input) override
{
ADD_FAILURE();
return NotReached("VerifyECDSASignedDigest should not be called",
Result::FATAL_ERROR_LIBRARY_FAILURE);
}
Result CheckRSAPublicKeyModulusSizeInBits(EndEntityOrCA, unsigned int)
override
{
ADD_FAILURE();
return NotReached("CheckRSAPublicKeyModulusSizeInBits should not be called",
Result::FATAL_ERROR_LIBRARY_FAILURE);
}
Result VerifyRSAPKCS1SignedDigest(const SignedDigest&, Input) override
{
ADD_FAILURE();
return NotReached("VerifyRSAPKCS1SignedDigest should not be called",
Result::FATAL_ERROR_LIBRARY_FAILURE);
}
};
class DefaultCryptoTrustDomain : public EverythingFailsByDefaultTrustDomain
{
Result DigestBuf(Input item, DigestAlgorithm digestAlg,
/*out*/ uint8_t* digestBuf, size_t digestBufLen) override
{
return TestDigestBuf(item, digestAlg, digestBuf, digestBufLen);
}
Result CheckSignatureDigestAlgorithm(DigestAlgorithm) override
{
return Success;
}
Result CheckECDSACurveIsAcceptable(EndEntityOrCA, NamedCurve) override
{
return Success;
}
Result VerifyECDSASignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyECDSASignedDigest(signedDigest, subjectPublicKeyInfo);
}
Result CheckRSAPublicKeyModulusSizeInBits(EndEntityOrCA, unsigned int)
override
{
return Success;
}
Result VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyRSAPKCS1SignedDigest(signedDigest, subjectPublicKeyInfo);
}
};
} } } // namespace mozilla::pkix::test
#endif // mozilla_pkix_pkixgtest_h
@@ -21,11 +21,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "pkix/pkix.h"
#include "pkixcheck.h"
#include "pkixder.h"
#include "pkixgtest.h"
#include "pkixtestutil.h"
#include "pkixutil.h"
namespace mozilla { namespace pkix {
@@ -23,42 +23,15 @@
*/
#include "pkixgtest.h"
#include "pkix/pkix.h"
#include "pkixder.h"
#include "pkixtestutil.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::test;
class CreateEncodedOCSPRequestTrustDomain final : public TrustDomain
class CreateEncodedOCSPRequestTrustDomain final
: public EverythingFailsByDefaultTrustDomain
{
private:
Result GetCertTrust(EndEntityOrCA, const CertPolicyId&, Input,
/*out*/ TrustLevel&) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result FindIssuer(Input, IssuerChecker&, Time) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, const Input*,
const Input*) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result IsChainValid(const DERArray&, Time) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result DigestBuf(Input item, DigestAlgorithm digestAlg,
/*out*/ uint8_t *digestBuf, size_t digestBufLen)
override
@@ -67,28 +40,9 @@ private:
}
Result CheckRSAPublicKeyModulusSizeInBits(EndEntityOrCA, unsigned int)
final override
override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result VerifyRSAPKCS1SignedDigest(const SignedDigest&, Input) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result CheckECDSACurveIsAcceptable(EndEntityOrCA, NamedCurve) final override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result VerifyECDSASignedDigest(const SignedDigest&, Input) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
return Success;
}
};
@@ -22,21 +22,18 @@
* limitations under the License.
*/
#include "pkix/pkix.h"
#include "pkixgtest.h"
#include "pkixtestutil.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::test;
const uint16_t END_ENTITY_MAX_LIFETIME_IN_DAYS = 10;
class OCSPTestTrustDomain : public TrustDomain
// Note that CheckRevocation is never called for OCSP signing certificates.
class OCSPTestTrustDomain : public DefaultCryptoTrustDomain
{
public:
OCSPTestTrustDomain()
{
}
OCSPTestTrustDomain() { }
Result GetCertTrust(EndEntityOrCA endEntityOrCA, const CertPolicyId&,
Input, /*out*/ TrustLevel& trustLevel)
@@ -46,62 +43,6 @@ public:
trustLevel = TrustLevel::InheritsTrust;
return Success;
}
Result FindIssuer(Input, IssuerChecker&, Time) final override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result CheckRevocation(EndEntityOrCA, const CertID&, Time,
/*optional*/ const Input*, /*optional*/ const Input*)
final override
{
// TODO: I guess mozilla::pkix should support revocation of designated
// OCSP responder eventually, but we don't now, so this function should
// never get called.
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result IsChainValid(const DERArray&, Time) final override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result DigestBuf(Input item, DigestAlgorithm digestAlg,
/*out*/ uint8_t* digestBuf, size_t digestBufLen)
final override
{
return TestDigestBuf(item, digestAlg, digestBuf, digestBufLen);
}
Result CheckRSAPublicKeyModulusSizeInBits(EndEntityOrCA, unsigned int)
final override
{
return Success;
}
Result VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyRSAPKCS1SignedDigest(signedDigest, subjectPublicKeyInfo);
}
Result CheckECDSACurveIsAcceptable(EndEntityOrCA, NamedCurve) final override
{
return Success;
}
Result VerifyECDSASignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyECDSASignedDigest(signedDigest, subjectPublicKeyInfo);
}
OCSPTestTrustDomain(const OCSPTestTrustDomain&) = delete;
void operator=(const OCSPTestTrustDomain&) = delete;
};
namespace {
+1
View File
@@ -24,6 +24,7 @@ catch (e) {
// under the "accessibility.*" branch.
const PREFS_WHITELIST = [
"accessibility.",
"apz.",
"browser.cache.",
"browser.display.",
"browser.download.folderList",
+2 -1
View File
@@ -1365,8 +1365,9 @@ function readStringFromInputStream(inputStream) {
sis.init(inputStream);
var text = sis.read(sis.available());
sis.close();
if (text[text.length - 1] == "\n")
if (text && text[text.length - 1] == "\n") {
text = text.slice(0, -1);
}
return text;
}
@@ -77,9 +77,8 @@ function runTest() {
removeDirRecursive(addonPrepDir);
}
catch (e) {
dump("Unable to remove directory\n" +
"path: " + addonPrepDir.path + "\n" +
"Exception: " + e + "\n");
logTestInfo("Unable to remove directory. Path: " + addonPrepDir.path +
", Exception: " + e);
}
resetAddons(finishTest);
+8 -6
View File
@@ -166,6 +166,8 @@ const TEST_ADDONS = [ "appdisabled_1", "appdisabled_2",
"updateversion_1", "updateversion_2",
"userdisabled_1", "userdisabled_2" ];
const LOG_FUNCTION = info;
var gURLData = URL_HOST + "/" + REL_PATH_DATA + "/";
var gTestTimeout = 240000; // 4 minutes
@@ -658,10 +660,11 @@ function waitForRemoteContentLoaded(aEvent) {
// expected or isn't the event's originalTarget.
if (gRemoteContentState != gTest.expectedRemoteContentState ||
aEvent.originalTarget != gRemoteContent) {
debugDump("returning early\n" +
"gRemoteContentState: " + gRemoteContentState + "\n" +
debugDump("returning early. " +
"gRemoteContentState: " +
gRemoteContentState + ", " +
"expectedRemoteContentState: " +
gTest.expectedRemoteContentState + "\n" +
gTest.expectedRemoteContentState + ", " +
"aEvent.originalTarget.nodeName: " +
aEvent.originalTarget.nodeName);
return true;
@@ -947,9 +950,8 @@ function resetFiles() {
removeDirRecursive(updatedDir);
}
catch (e) {
dump("Unable to remove directory\n" +
"path: " + updatedDir.path + "\n" +
"Exception: " + e + "\n");
logTestInfo("Unable to remove directory. Path: " + updatedDir.path +
", Exception: " + e);
}
}
}
+13 -12
View File
@@ -430,8 +430,8 @@ function removeUpdateDirsAndFiles() {
if (file.exists())
file.remove(false);
} catch (e) {
dump("Unable to remove file\nPath: " + file.path +
"\nException: " + e + "\n");
logTestInfo("Unable to remove file. Path: " + file.path +
", Exception: " + e);
}
file = getUpdatesXMLFile(false);
@@ -439,8 +439,8 @@ function removeUpdateDirsAndFiles() {
if (file.exists())
file.remove(false);
} catch (e) {
dump("Unable to remove file\nPath: " + file.path +
"\nException: " + e + "\n");
logTestInfo("Unable to remove file. Path: " + file.path +
", Exception: " + e);
}
// This fails sporadically on Mac OS X so wrap it in a try catch
@@ -448,8 +448,8 @@ function removeUpdateDirsAndFiles() {
try {
cleanUpdatesDir(updatesDir);
} catch (e) {
dump("Unable to remove files / directories from directory\nPath: " +
updatesDir.path + "\nException: " + e + "\n");
logTestInfo("Unable to remove files / directories from directory. Path: " +
updatesDir.path + ", Exception: " + e);
}
}
@@ -483,8 +483,8 @@ function cleanUpdatesDir(aDir) {
try {
entry.remove(true);
} catch (e) {
dump("cleanUpdatesDir: unable to remove directory\nPath: " +
entry.path + "\nException: " + e + "\n");
logTestInfo("cleanUpdatesDir: unable to remove directory. Path: " +
entry.path + ", Exception: " + e);
throw(e);
}
}
@@ -493,8 +493,8 @@ function cleanUpdatesDir(aDir) {
try {
entry.remove(false);
} catch (e) {
dump("cleanUpdatesDir: unable to remove file\nPath: " + entry.path +
"\nException: " + e + "\n");
logTestInfo("cleanUpdatesDir: unable to remove file. Path: " +
entry.path + ", Exception: " + e);
throw(e);
}
}
@@ -614,8 +614,9 @@ function logTestInfo(aText, aCaller) {
(mm < 10 ? "0" + mm : mm) + ":" +
(ss < 10 ? "0" + ss : ss) + ":" +
(ms < 10 ? "00" + ms : ms < 100 ? "0" + ms : ms);
dump(time + " | TEST-INFO | " + caller.filename + " | [" + caller.name +
" : " + caller.lineNumber + "] " + aText + "\n");
let msg = time + " | TEST-INFO | " + caller.filename + " | [" + caller.name +
" : " + caller.lineNumber + "] " + aText;
LOG_FUNCTION(msg);
}
/**
@@ -61,74 +61,84 @@ function run_test() {
doTestFinish();
}
if (IS_WIN) {
/**
* Determines a unique mutex name for the installation.
*
* @return Global mutex path.
*/
function getPerInstallationMutexName() {
let hasher = AUS_Cc["@mozilla.org/security/hash;1"].
createInstance(AUS_Ci.nsICryptoHash);
hasher.init(hasher.SHA1);
let exeFile = Services.dirsvc.get(XRE_EXECUTABLE_FILE, AUS_Ci.nsILocalFile);
let converter = AUS_Cc["@mozilla.org/intl/scriptableunicodeconverter"].
createInstance(AUS_Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
let data = converter.convertToByteArray(exeFile.path.toLowerCase());
hasher.update(data, data.length);
return "Global\\MozillaUpdateMutex-" + hasher.finish(true);
/**
* Determines a unique mutex name for the installation.
*
* @return Global mutex path.
*/
function getPerInstallationMutexName() {
if (!IS_WIN) {
do_throw("Windows only function called by a different platform!");
}
/**
* Closes a Win32 handle.
*
* @param aHandle
* The handle to close.
*/
function closeHandle(aHandle) {
let lib = ctypes.open("kernel32.dll");
let CloseHandle = lib.declare("CloseHandle",
ctypes.winapi_abi,
ctypes.int32_t, /* success */
ctypes.void_t.ptr); /* handle */
CloseHandle(aHandle);
lib.close();
}
let hasher = AUS_Cc["@mozilla.org/security/hash;1"].
createInstance(AUS_Ci.nsICryptoHash);
hasher.init(hasher.SHA1);
/**
* Creates a mutex.
*
* @param aName
* The name for the mutex.
* @return The Win32 handle to the mutex.
*/
function createMutex(aName) {
const INITIAL_OWN = 1;
const ERROR_ALREADY_EXISTS = 0xB7;
let lib = ctypes.open("kernel32.dll");
let CreateMutexW = lib.declare("CreateMutexW",
ctypes.winapi_abi,
ctypes.void_t.ptr, /* return handle */
ctypes.void_t.ptr, /* security attributes */
ctypes.int32_t, /* initial owner */
ctypes.char16_t.ptr); /* name */
let exeFile = Services.dirsvc.get(XRE_EXECUTABLE_FILE, AUS_Ci.nsILocalFile);
let handle = CreateMutexW(null, INITIAL_OWN, aName);
lib.close();
let alreadyExists = ctypes.winLastError == ERROR_ALREADY_EXISTS;
if (handle && !handle.isNull() && alreadyExists) {
closeHandle(handle);
handle = null;
}
let converter = AUS_Cc["@mozilla.org/intl/scriptableunicodeconverter"].
createInstance(AUS_Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
let data = converter.convertToByteArray(exeFile.path.toLowerCase());
if (handle && handle.isNull()) {
handle = null;
}
return handle;
}
hasher.update(data, data.length);
return "Global\\MozillaUpdateMutex-" + hasher.finish(true);
}
/**
* Closes a Win32 handle.
*
* @param aHandle
* The handle to close.
*/
function closeHandle(aHandle) {
if (!IS_WIN) {
do_throw("Windows only function called by a different platform!");
}
let lib = ctypes.open("kernel32.dll");
let CloseHandle = lib.declare("CloseHandle",
ctypes.winapi_abi,
ctypes.int32_t, /* success */
ctypes.void_t.ptr); /* handle */
CloseHandle(aHandle);
lib.close();
}
/**
* Creates a mutex.
*
* @param aName
* The name for the mutex.
* @return The Win32 handle to the mutex.
*/
function createMutex(aName) {
if (!IS_WIN) {
do_throw("Windows only function called by a different platform!");
}
const INITIAL_OWN = 1;
const ERROR_ALREADY_EXISTS = 0xB7;
let lib = ctypes.open("kernel32.dll");
let CreateMutexW = lib.declare("CreateMutexW",
ctypes.winapi_abi,
ctypes.void_t.ptr, /* return handle */
ctypes.void_t.ptr, /* security attributes */
ctypes.int32_t, /* initial owner */
ctypes.char16_t.ptr); /* name */
let handle = CreateMutexW(null, INITIAL_OWN, aName);
lib.close();
let alreadyExists = ctypes.winLastError == ERROR_ALREADY_EXISTS;
if (handle && !handle.isNull() && alreadyExists) {
closeHandle(handle);
handle = null;
}
if (handle && handle.isNull()) {
handle = null;
}
return handle;
}
@@ -36,7 +36,7 @@ function run_test() {
do_check_eq(gUpdateManager.activeUpdate, null);
// Verify that the active-update.xml file has had the update from the old
// channel removed.
file = getUpdatesXMLFile(true);
let file = getUpdatesXMLFile(true);
logTestInfo("verifying contents of " + FILE_UPDATE_ACTIVE);
do_check_eq(readFile(file), getLocalUpdatesXMLString(""));
@@ -5,7 +5,10 @@
const KEY_UPDATE_ARCHIVE_DIR = "UpdArchD"
let gActiveUpdate = null;
let gActiveUpdate;
let gDirService;
let gDirProvider;
let gOldProviders;
function FakeDirProvider() {}
FakeDirProvider.prototype = {
@@ -152,7 +152,7 @@ IncrementalDownload.prototype = {
tm.mainThread.dispatch(function() {
this._observer = observer.QueryInterface(AUS_Ci.nsIRequestObserver);
this._ctxt = ctxt;
this._observer.onStartRequest(this, this.ctxt);
this._observer.onStartRequest(this, this._ctxt);
let mar = getTestDirFile(FILE_SIMPLE_MAR);
mar.copyTo(this._destination.parent, this._destination.leafName);
var status = AUS_Cr.NS_OK
@@ -2,6 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const INSTALL_LOCALE = "@AB_CD@";
const MOZ_APP_NAME = "@MOZ_APP_NAME@";
const BIN_SUFFIX = "@BIN_SUFFIX@";
@@ -140,6 +142,8 @@ const PIPE_TO_NULL = ">nul";
const PIPE_TO_NULL = "> /dev/null 2>&1";
#endif
const LOG_FUNCTION = do_print;
// This default value will be overridden when using the http server.
var gURLData = URL_HOST + "/";
@@ -1451,41 +1455,46 @@ function getMockUpdRootD() {
}
#endif
if (IS_WIN) {
const kLockFileName = "updated.update_in_progress.lock";
/**
* Helper function for locking a directory on Windows.
*
* @param aDir
* The nsIFile for the directory to lock.
*/
function lockDirectory(aDir) {
var file = aDir.clone();
file.append(kLockFileName);
file.create(file.NORMAL_FILE_TYPE, 0o444);
file.QueryInterface(AUS_Ci.nsILocalFileWin);
file.fileAttributesWin |= file.WFA_READONLY;
file.fileAttributesWin &= ~file.WFA_READWRITE;
logTestInfo("testing the successful creation of the lock file");
do_check_true(file.exists());
do_check_false(file.isWritable());
const kLockFileName = "updated.update_in_progress.lock";
/**
* Helper function for locking a directory on Windows.
*
* @param aDir
* The nsIFile for the directory to lock.
*/
function lockDirectory(aDir) {
if (!IS_WIN) {
do_throw("Windows only function called by a different platform!");
}
/**
* Helper function for unlocking a directory on Windows.
*
* @param aDir
* The nsIFile for the directory to unlock.
*/
function unlockDirectory(aDir) {
var file = aDir.clone();
file.append(kLockFileName);
file.QueryInterface(AUS_Ci.nsILocalFileWin);
file.fileAttributesWin |= file.WFA_READWRITE;
file.fileAttributesWin &= ~file.WFA_READONLY;
logTestInfo("removing and testing the successful removal of the lock file");
file.remove(false);
do_check_false(file.exists());
let file = aDir.clone();
file.append(kLockFileName);
file.create(file.NORMAL_FILE_TYPE, 0o444);
file.QueryInterface(AUS_Ci.nsILocalFileWin);
file.fileAttributesWin |= file.WFA_READONLY;
file.fileAttributesWin &= ~file.WFA_READWRITE;
logTestInfo("testing the successful creation of the lock file");
do_check_true(file.exists());
do_check_false(file.isWritable());
}
/**
* Helper function for unlocking a directory on Windows.
*
* @param aDir
* The nsIFile for the directory to unlock.
*/
function unlockDirectory(aDir) {
if (!IS_WIN) {
do_throw("Windows only function called by a different platform!");
}
let file = aDir.clone();
file.append(kLockFileName);
file.QueryInterface(AUS_Ci.nsILocalFileWin);
file.fileAttributesWin |= file.WFA_READWRITE;
file.fileAttributesWin &= ~file.WFA_READONLY;
logTestInfo("removing and testing the successful removal of the lock file");
file.remove(false);
do_check_false(file.exists());
}
/**
@@ -3253,7 +3262,7 @@ function start_httpserver() {
if (!dir.isDirectory()) {
do_throw("A file instead of a directory was specified for HttpServer " +
"registerDirectory! Path: " + dir.path + "\n");
"registerDirectory! Path: " + dir.path);
}
AUS_Cu.import("resource://testing-common/httpd.js");
@@ -3663,7 +3672,7 @@ function setEnvironment() {
env.set("XPCOM_DEBUG_BREAK", "warn");
if (gStageUpdate) {
logTestInfo("setting the MOZ_UPDATE_STAGING environment variable to 1\n");
logTestInfo("setting the MOZ_UPDATE_STAGING environment variable to 1");
env.set("MOZ_UPDATE_STAGING", "1");
}
@@ -3729,7 +3738,7 @@ function resetEnvironment() {
}
if (gStageUpdate) {
logTestInfo("removing the MOZ_UPDATE_STAGING environment variable\n");
logTestInfo("removing the MOZ_UPDATE_STAGING environment variable");
env.set("MOZ_UPDATE_STAGING", "");
}
@@ -14,8 +14,6 @@ function run_test() {
// The mock XMLHttpRequest is MUCH faster
overrideXHR(callHandleEvent);
standardInit();
// The HTTP server is only used for the mar file downloads which is slow
start_httpserver();
let registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar);
registrar.registerFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"),
@@ -5,6 +5,8 @@
/* General Update Timer Manager Tests */
'use strict';
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cm = Components.manager;
@@ -103,8 +105,8 @@ const TESTS = [ {
lastUpdateTime : 0
} ];
var gUTM;
var gNextFunc;
let gUTM;
let gNextFunc;
XPCOMUtils.defineLazyServiceGetter(this, "gPref",
"@mozilla.org/preferences-service;1",
@@ -127,7 +129,7 @@ function run_test() {
gPref.setBoolPref(PREF_APP_UPDATE_LOG_ALL, true);
// Remove existing update timers to prevent them from being notified
var entries = gCatMan.enumerateCategory(CATEGORY_UPDATE_TIMER);
let entries = gCatMan.enumerateCategory(CATEGORY_UPDATE_TIMER);
while (entries.hasMoreElements()) {
let entry = entries.getNext().QueryInterface(Ci.nsISupportsCString).data;
gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, entry, false);
@@ -165,7 +167,7 @@ function run_test1thru7() {
TESTS[1].defaultInterval].join(","), false, true);
// has a last update time of now - 43200 which is half of its interval
var lastUpdateTime = Math.round(Date.now() / 1000) - 43200;
let lastUpdateTime = Math.round(Date.now() / 1000) - 43200;
gPref.setIntPref(PREF_BRANCH_LAST_UPDATE_TIME + TESTS[2].timerID, lastUpdateTime);
gCompReg.registerFactory(TESTS[2].classID, TESTS[2].desc,
TESTS[2].contractID, gTest3Factory);
@@ -201,7 +203,7 @@ function run_test1thru7() {
TESTS[5].defaultInterval].join(","), false, true);
// has a next update time 24 hours from now
var nextUpdateTime = Math.round(Date.now() / 1000) + 86400;
let nextUpdateTime = Math.round(Date.now() / 1000) + 86400;
gPref.setIntPref(PREF_BRANCH_LAST_UPDATE_TIME + TESTS[6].timerID, nextUpdateTime);
gCompReg.registerFactory(TESTS[6].classID, TESTS[6].desc,
TESTS[6].contractID, gTest7Factory);
@@ -212,40 +214,41 @@ function run_test1thru7() {
}
function finished_test1thru7() {
if (TESTS[4].notified && TESTS[5].notified && TESTS[6].notified)
if (TESTS[4].notified && TESTS[5].notified && TESTS[6].notified) {
do_timeout(0, gNextFunc);
}
}
function check_test1thru7() {
dump("Testing: a category registered timer didn't fire due to an invalid " +
"default interval\n");
do_print("Testing: a category registered timer didn't fire due to an " +
"invalid default interval");
do_check_false(TESTS[0].notified);
dump("Testing: a category registered timer didn't fire due to not " +
"implementing nsITimerCallback\n");
do_print("Testing: a category registered timer didn't fire due to not " +
"implementing nsITimerCallback");
do_check_false(TESTS[1].notified);
dump("Testing: a category registered timer didn't fire due to the next " +
"update time being in the future\n");
do_print("Testing: a category registered timer didn't fire due to the next " +
"update time being in the future");
do_check_false(TESTS[2].notified);
dump("Testing: a category registered timer didn't fire due to not " +
"having a notify method\n");
do_print("Testing: a category registered timer didn't fire due to not " +
"having a notify method");
do_check_false(TESTS[3].notified);
dump("Testing: a category registered timer has fired\n");
do_print("Testing: a category registered timer has fired");
do_check_true(TESTS[4].notified);
dump("Testing: a category registered timer fired that has an interval " +
"preference that overrides a default that wouldn't have fired yet\n");
do_print("Testing: a category registered timer fired that has an interval " +
"preference that overrides a default that wouldn't have fired yet");
do_check_true(TESTS[5].notified);
dump("Testing: a category registered timer has fired due to the next " +
"update time being reset due to a future last update time\n");
do_print("Testing: a category registered timer has fired due to the next " +
"update time being reset due to a future last update time");
do_check_true(TESTS[6].notified);
dump("Testing: two category registered timers last update time has " +
"user values\n");
do_print("Testing: two category registered timers last update time has " +
"user values");
do_check_true(gPref.prefHasUserValue(PREF_BRANCH_LAST_UPDATE_TIME +
TESTS[4].timerID));
do_check_true(gPref.prefHasUserValue(PREF_BRANCH_LAST_UPDATE_TIME +
@@ -256,23 +259,22 @@ function check_test1thru7() {
gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[1].desc, true);
gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[2].desc, true);
gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[3].desc, true);
var count = 0;
var entries = gCatMan.enumerateCategory(CATEGORY_UPDATE_TIMER);
let count = 0;
let entries = gCatMan.enumerateCategory(CATEGORY_UPDATE_TIMER);
while (entries.hasMoreElements()) {
let entry = entries.getNext().QueryInterface(Ci.nsISupportsCString).data;
gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, entry, false);
count++;
}
dump("Testing: no " + CATEGORY_UPDATE_TIMER + " categories are still " +
"registered\n");
do_print("Testing: no " + CATEGORY_UPDATE_TIMER + " categories are still " +
"registered");
do_check_eq(count, 0);
do_timeout(0, run_test8);
}
function run_test8() {
gNextFunc = check_test8;
for (var i = 0; i < 2; i++) {
for (let i = 0; i < 2; i++) {
gPref.setIntPref(PREF_BRANCH_LAST_UPDATE_TIME + TESTS[7 + i].timerID, 1);
gCompReg.registerFactory(TESTS[7 + i].classID, TESTS[7 + i].desc,
TESTS[7 + i].contractID, eval("gTest" + (8 + i) + "Factory"));
@@ -281,15 +283,16 @@ function run_test8() {
}
}
function check_test8() {
var self = arguments.callee;
self.timesCalled = (self.timesCalled || 0) + 1;
if (self.timesCalled < 2)
function check_test8(aTestTimerCallback) {
aTestTimerCallback.timesCalled = (aTestTimerCallback.timesCalled || 0) + 1;
if (aTestTimerCallback.timesCalled < 2) {
return;
}
dump("Testing: two registerTimer registered timers have fired\n");
for (var i = 0; i < 2; i++)
do_print("Testing: two registerTimer registered timers have fired");
for (let i = 0; i < 2; i++) {
do_check_true(TESTS[7 + i].notified);
}
// Check that 'staggering' has happened: even though the two events wanted to fire at
// the same time, we waited a full MAIN_TIMER_INTERVAL between them.
@@ -297,71 +300,76 @@ function check_test8() {
do_check_true(Math.abs(TESTS[7].notifyTime - TESTS[8].notifyTime) >=
MAIN_TIMER_INTERVAL * 0.5);
dump("Testing: two registerTimer registered timers last update time have " +
"been updated\n");
for (var i = 0; i < 2; i++)
do_print("Testing: two registerTimer registered timers last update time have " +
"been updated");
for (let i = 0; i < 2; i++) {
do_check_neq(gPref.getIntPref(PREF_BRANCH_LAST_UPDATE_TIME + TESTS[7 + i].timerID), 1);
}
end_test();
}
var gTest1TimerCallback = {
const gTest1TimerCallback = {
notify: function T1CB_notify(aTimer) {
do_throw("gTest1TimerCallback notify method should not have been called");
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
};
var gTest1Factory = {
const gTest1Factory = {
createInstance: function (outer, iid) {
if (outer == null)
if (outer == null) {
return gTest1TimerCallback.QueryInterface(iid);
}
throw Cr.NS_ERROR_NO_AGGREGATION;
}
};
var gTest2TimerCallback = {
const gTest2TimerCallback = {
notify: function T2CB_notify(aTimer) {
do_throw("gTest2TimerCallback notify method should not have been called");
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsITimer])
};
var gTest2Factory = {
const gTest2Factory = {
createInstance: function (outer, iid) {
if (outer == null)
if (outer == null) {
return gTest2TimerCallback.QueryInterface(iid);
}
throw Cr.NS_ERROR_NO_AGGREGATION;
}
};
var gTest3TimerCallback = {
const gTest3TimerCallback = {
notify: function T3CB_notify(aTimer) {
do_throw("gTest3TimerCallback notify method should not have been called");
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
};
var gTest3Factory = {
const gTest3Factory = {
createInstance: function (outer, iid) {
if (outer == null)
if (outer == null) {
return gTest3TimerCallback.QueryInterface(iid);
}
throw Cr.NS_ERROR_NO_AGGREGATION;
}
};
var gTest4TimerCallback = {
const gTest4TimerCallback = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
};
var gTest4Factory = {
const gTest4Factory = {
createInstance: function (outer, iid) {
if (outer == null)
if (outer == null) {
return gTest4TimerCallback.QueryInterface(iid);
}
throw Cr.NS_ERROR_NO_AGGREGATION;
}
};
var gTest5TimerCallback = {
const gTest5TimerCallback = {
notify: function T5CB_notify(aTimer) {
gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[4].desc, true);
TESTS[4].notified = true;
@@ -370,15 +378,16 @@ var gTest5TimerCallback = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
};
var gTest5Factory = {
const gTest5Factory = {
createInstance: function (outer, iid) {
if (outer == null)
if (outer == null) {
return gTest5TimerCallback.QueryInterface(iid);
}
throw Cr.NS_ERROR_NO_AGGREGATION;
}
};
var gTest6TimerCallback = {
const gTest6TimerCallback = {
notify: function T6CB_notify(aTimer) {
gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[5].desc, true);
TESTS[5].notified = true;
@@ -387,15 +396,16 @@ var gTest6TimerCallback = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
};
var gTest6Factory = {
const gTest6Factory = {
createInstance: function (outer, iid) {
if (outer == null)
if (outer == null) {
return gTest6TimerCallback.QueryInterface(iid);
}
throw Cr.NS_ERROR_NO_AGGREGATION;
}
};
var gTest7TimerCallback = {
const gTest7TimerCallback = {
notify: function T7CB_notify(aTimer) {
gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[6].desc, true);
TESTS[6].notified = true;
@@ -404,44 +414,51 @@ var gTest7TimerCallback = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
};
var gTest7Factory = {
const gTest7Factory = {
createInstance: function (outer, iid) {
if (outer == null)
if (outer == null) {
return gTest7TimerCallback.QueryInterface(iid);
}
throw Cr.NS_ERROR_NO_AGGREGATION;
}
};
var gTest8TimerCallback = {
const gTest8TimerCallback = {
notify: function T8CB_notify(aTimer) {
TESTS[7].notified = true;
TESTS[7].notifyTime = Date.now();
do_timeout(0, check_test8);
do_timeout(0, function() {
check_test8(gTest8TimerCallback);
});
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
};
var gTest8Factory = {
const gTest8Factory = {
createInstance: function (outer, iid) {
if (outer == null)
if (outer == null) {
return gTest8TimerCallback.QueryInterface(iid);
}
throw Cr.NS_ERROR_NO_AGGREGATION;
}
};
var gTest9TimerCallback = {
const gTest9TimerCallback = {
notify: function T9CB_notify(aTimer) {
TESTS[8].notified = true;
TESTS[8].notifyTime = Date.now();
do_timeout(0, check_test8);
do_timeout(0, function() {
check_test8(gTest9TimerCallback);
});
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
};
var gTest9Factory = {
const gTest9Factory = {
createInstance: function (outer, iid) {
if (outer == null)
if (outer == null) {
return gTest9TimerCallback.QueryInterface(iid);
}
throw Cr.NS_ERROR_NO_AGGREGATION;
}
};