diff --git a/editor/composer/test/test_bug519928.html b/editor/composer/test/test_bug519928.html index 6b6f59e48d..3b1a9ba175 100644 --- a/editor/composer/test/test_bug519928.html +++ b/editor/composer/test/test_bug519928.html @@ -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() { - diff --git a/editor/libeditor/tests/test_CF_HTML_clipboard.html b/editor/libeditor/tests/test_CF_HTML_clipboard.html index f50b467321..4949f40b38 100644 --- a/editor/libeditor/tests/test_CF_HTML_clipboard.html +++ b/editor/libeditor/tests/test_CF_HTML_clipboard.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(); diff --git a/editor/libeditor/tests/test_bug520189.html b/editor/libeditor/tests/test_bug520189.html index 3571e230e0..d1b429000e 100644 --- a/editor/libeditor/tests/test_bug520189.html +++ b/editor/libeditor/tests/test_bug520189.html @@ -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(" #include #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); } diff --git a/gfx/2d/DrawTargetTiled.cpp b/gfx/2d/DrawTargetTiled.cpp index 8b419ed5e4..31717577bd 100644 --- a/gfx/2d/DrawTargetTiled.cpp +++ b/gfx/2d/DrawTargetTiled.cpp @@ -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 - #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) { diff --git a/gfx/2d/PathHelpers.cpp b/gfx/2d/PathHelpers.cpp index b9c0a3c1fd..e28f4f053f 100644 --- a/gfx/2d/PathHelpers.cpp +++ b/gfx/2d/PathHelpers.cpp @@ -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 + #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 diff --git a/gfx/2d/PathHelpers.h b/gfx/2d/PathHelpers.h index e55049d732..c1a8ffc36f 100644 --- a/gfx/2d/PathHelpers.h +++ b/gfx/2d/PathHelpers.h @@ -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; /** diff --git a/gfx/2d/moz.build b/gfx/2d/moz.build index 3b30e92967..3ed8e88e82 100644 --- a/gfx/2d/moz.build +++ b/gfx/2d/moz.build @@ -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': diff --git a/gfx/ipc/GfxMessageUtils.h b/gfx/ipc/GfxMessageUtils.h index 16cfde0261..0b67490773 100644 --- a/gfx/ipc/GfxMessageUtils.h +++ b/gfx/ipc/GfxMessageUtils.h @@ -277,21 +277,6 @@ struct ParamTraits mozilla::layers::TextureFlags::ALL_BITS> {}; -template <> -struct ParamTraits - : public ContiguousEnumSerializer< - mozilla::layers::TextureIdentifier, - mozilla::layers::TextureIdentifier::Front, - mozilla::layers::TextureIdentifier::HighBound> -{}; - -template <> -struct ParamTraits - : public BitFlagsEnumSerializer< - mozilla::layers::DeprecatedTextureHostFlags, - mozilla::layers::DeprecatedTextureHostFlags::ALL_BITS> -{}; - template <> struct ParamTraits : public BitFlagsEnumSerializer< @@ -850,14 +835,12 @@ struct ParamTraits 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); } }; diff --git a/gfx/layers/CompositorTypes.h b/gfx/layers/CompositorTypes.h index 3fa70406c2..b76492b5a9 100644 --- a/gfx/layers/CompositorTypes.h +++ b/gfx/layers/CompositorTypes.h @@ -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; } }; diff --git a/gfx/layers/RotatedBuffer.h b/gfx/layers/RotatedBuffer.h index f6e8de0f9c..dbffc949b1 100644 --- a/gfx/layers/RotatedBuffer.h +++ b/gfx/layers/RotatedBuffer.h @@ -272,7 +272,6 @@ public: struct DrawIterator { friend class RotatedContentBuffer; - friend class ContentClientIncremental; DrawIterator() : mCount(0) {} diff --git a/gfx/layers/basic/BasicCompositor.cpp b/gfx/layers/basic/BasicCompositor.cpp index 9f404c719f..e8af9e0de2 100644 --- a/gfx/layers/basic/BasicCompositor.cpp +++ b/gfx/layers/basic/BasicCompositor.cpp @@ -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; } diff --git a/gfx/layers/client/ClientLayerManager.cpp b/gfx/layers/client/ClientLayerManager.cpp index a5feb60da0..48a964121b 100644 --- a/gfx/layers/client/ClientLayerManager.cpp +++ b/gfx/layers/client/ClientLayerManager.cpp @@ -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(); diff --git a/gfx/layers/client/CompositableClient.h b/gfx/layers/client/CompositableClient.h index 6bf851451d..892c6a8768 100644 --- a/gfx/layers/client/CompositableClient.h +++ b/gfx/layers/client/CompositableClient.h @@ -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 */ diff --git a/gfx/layers/client/ContentClient.cpp b/gfx/layers/client/ContentClient.cpp index 1ac23e3bfd..f788fb1bfb 100644 --- a/gfx/layers/client/ContentClient.cpp +++ b/gfx/layers/client/ContentClient.cpp @@ -93,11 +93,6 @@ ContentClient::CreateContentClient(CompositableForwarder* aForwarder) if (useDoubleBuffering || PR_GetEnv("MOZ_FORCE_DOUBLE_BUFFERING")) { return MakeAndAddRef(aForwarder); } -#ifdef XP_MACOSX - if (backend == LayersBackend::LAYERS_OPENGL) { - return MakeAndAddRef(aForwarder); - } -#endif return MakeAndAddRef(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 onBlack = GetUpdateSurface(BUFFER_BLACK, drawRegionCopy); - RefPtr 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 -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); -} - } } diff --git a/gfx/layers/client/ContentClient.h b/gfx/layers/client/ContentClient.h index 03f081f900..9d6884036e 100644 --- a/gfx/layers/client/ContentClient.h +++ b/gfx/layers/client/ContentClient.h @@ -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* 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 GetUpdateSurface(BufferType aType, - const nsIntRegion& aUpdateRegion); - - TextureInfo mTextureInfo; - nsIntRect mBufferRect; - nsIntPoint mBufferRotation; - - SurfaceDescriptor mUpdateDescriptor; - SurfaceDescriptor mUpdateDescriptorOnWhite; - - ContentType mContentType; - - bool mHasBuffer; - bool mHasBufferOnWhite; -}; - } } diff --git a/gfx/layers/composite/CompositableHost.cpp b/gfx/layers/composite/CompositableHost.cpp index 495a55277d..67ca5633d7 100644 --- a/gfx/layers/composite/CompositableHost.cpp +++ b/gfx/layers/composite/CompositableHost.cpp @@ -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; diff --git a/gfx/layers/composite/CompositableHost.h b/gfx/layers/composite/CompositableHost.h index 1af02dee22..8d620164e4 100644 --- a/gfx/layers/composite/CompositableHost.h +++ b/gfx/layers/composite/CompositableHost.h @@ -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. */ diff --git a/gfx/layers/composite/ContentHost.cpp b/gfx/layers/composite/ContentHost.cpp index 939fa9498e..a3ed579950 100644 --- a/gfx/layers/composite/ContentHost.cpp +++ b/gfx/layers/composite/ContentHost.cpp @@ -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 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 temp = - compositor->CreateDataTextureSource(mTextureInfo.mTextureFlags); - MOZ_ASSERT(temp->AsSourceOGL() && - temp->AsSourceOGL()->AsTextureImageTextureSource()); - RefPtr newSource = - temp->AsSourceOGL()->AsTextureImageTextureSource(); - - RefPtr 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 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 -ContentHostIncremental::GenEffect(const gfx::Filter& aFilter) -{ - if (!mSource) { - return nullptr; - } - return CreateTexturedEffect(mSource, mSourceOnWhite, aFilter, true); -} - already_AddRefed ContentHostTexture::GetAsSurface() { diff --git a/gfx/layers/composite/ContentHost.h b/gfx/layers/composite/ContentHost.h index c7fb7745ae..49db5a1651 100644 --- a/gfx/layers/composite/ContentHost.h +++ b/gfx/layers/composite/ContentHost.h @@ -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 - 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 mDeAllocator; - TextureIdentifier mTextureId; - SurfaceDescriptor mDescriptor; - nsIntRegion mUpdated; - nsIntRect mBufferRect; - nsIntPoint mBufferRotation; - }; - - nsTArray > mUpdateList; - - // Specific to OGL to avoid exposing methods on TextureSource that only - // have one implementation. - RefPtr mSource; - RefPtr mSourceOnWhite; - - RefPtr mDeAllocator; - bool mLocked; -}; - } } diff --git a/gfx/layers/composite/PaintedLayerComposite.cpp b/gfx/layers/composite/PaintedLayerComposite.cpp index 146197b01b..1adc15c966 100644 --- a/gfx/layers/composite/PaintedLayerComposite.cpp +++ b/gfx/layers/composite/PaintedLayerComposite.cpp @@ -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: diff --git a/gfx/layers/ipc/CompositableForwarder.h b/gfx/layers/ipc/CompositableForwarder.h index 12856eb38f..5fe9423046 100644 --- a/gfx/layers/ipc/CompositableForwarder.h +++ b/gfx/layers/ipc/CompositableForwarder.h @@ -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 */ diff --git a/gfx/layers/ipc/CompositableTransactionParent.cpp b/gfx/layers/ipc/CompositableTransactionParent.cpp index fbfdc74861..025ac8848b 100644 --- a/gfx/layers/ipc/CompositableTransactionParent.cpp +++ b/gfx/layers/ipc/CompositableTransactionParent.cpp @@ -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); diff --git a/gfx/layers/ipc/ImageBridgeChild.cpp b/gfx/layers/ipc/ImageBridgeChild.cpp index cd2e2b76b0..2b74ae106f 100644 --- a/gfx/layers/ipc/ImageBridgeChild.cpp +++ b/gfx/layers/ipc/ImageBridgeChild.cpp @@ -541,17 +541,6 @@ ImageBridgeChild::EndTransaction() for (nsTArray::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(); diff --git a/gfx/layers/ipc/ImageBridgeChild.h b/gfx/layers/ipc/ImageBridgeChild.h index d0e4a68add..c9be164806 100644 --- a/gfx/layers/ipc/ImageBridgeChild.h +++ b/gfx/layers/ipc/ImageBridgeChild.h @@ -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 { diff --git a/gfx/layers/ipc/LayersMessages.ipdlh b/gfx/layers/ipc/LayersMessages.ipdlh index d03d65f872..ec59d7a015 100644 --- a/gfx/layers/ipc/LayersMessages.ipdlh +++ b/gfx/layers/ipc/LayersMessages.ipdlh @@ -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; }; diff --git a/gfx/layers/ipc/ShadowLayers.cpp b/gfx/layers/ipc/ShadowLayers.cpp index 59a043cbc3..7e744fdad2 100644 --- a/gfx/layers/ipc/ShadowLayers.cpp +++ b/gfx/layers/ipc/ShadowLayers.cpp @@ -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) { diff --git a/gfx/layers/ipc/ShadowLayers.h b/gfx/layers/ipc/ShadowLayers.h index af0994ae83..360d07fd22 100644 --- a/gfx/layers/ipc/ShadowLayers.h +++ b/gfx/layers/ipc/ShadowLayers.h @@ -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 */ diff --git a/layout/generic/nsLineLayout.cpp b/layout/generic/nsLineLayout.cpp index 2f48b10fbf..14d98e9f45 100644 --- a/layout/generic/nsLineLayout.cpp +++ b/layout/generic/nsLineLayout.cpp @@ -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)); } diff --git a/layout/generic/nsLineLayout.h b/layout/generic/nsLineLayout.h index 667442856f..2bfad7f875 100644 --- a/layout/generic/nsLineLayout.h +++ b/layout/generic/nsLineLayout.h @@ -686,7 +686,6 @@ protected: nscoord aDeltaISize); void ApplyLineJustificationToAnnotations(PerFrameData* aPFD, - PerSpanData* aContainingSpan, nscoord aDeltaICoord, nscoord aDeltaISize); diff --git a/layout/reftests/writing-mode/1135361-ruby-justify-1-ref.html b/layout/reftests/writing-mode/1135361-ruby-justify-1-ref.html new file mode 100644 index 0000000000..d7d64b3fa9 --- /dev/null +++ b/layout/reftests/writing-mode/1135361-ruby-justify-1-ref.html @@ -0,0 +1,45 @@ + + + + + Test for bug 1135361 + + + +
+

+ to +

+
+
+

+ kyo +

+
+ + diff --git a/layout/reftests/writing-mode/1135361-ruby-justify-1.html b/layout/reftests/writing-mode/1135361-ruby-justify-1.html new file mode 100644 index 0000000000..810a4e5908 --- /dev/null +++ b/layout/reftests/writing-mode/1135361-ruby-justify-1.html @@ -0,0 +1,46 @@ + + + + + Test for bug 1135361 + + + +
+

+ tokyo +

+
+
+

+ tokyo +

+
+ + diff --git a/layout/reftests/writing-mode/reftest.list b/layout/reftests/writing-mode/reftest.list index 860a361597..3d4e77b320 100644 --- a/layout/reftests/writing-mode/reftest.list +++ b/layout/reftests/writing-mode/reftest.list @@ -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 diff --git a/python/mozbuild/mozbuild/frontend/context.py b/python/mozbuild/mozbuild/frontend/context.py index 84cf9583ed..cb96b77c19 100644 --- a/python/mozbuild/mozbuild/frontend/context.py +++ b/python/mozbuild/mozbuild/frontend/context.py @@ -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) diff --git a/security/apps/AppTrustDomain.cpp b/security/apps/AppTrustDomain.cpp index 96bf944315..8ca6e8b6fc 100644 --- a/security/apps/AppTrustDomain.cpp +++ b/security/apps/AppTrustDomain.cpp @@ -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); } diff --git a/security/apps/AppTrustDomain.h b/security/apps/AppTrustDomain.h index 5d0a017c25..ff414e63dc 100644 --- a/security/apps/AppTrustDomain.h +++ b/security/apps/AppTrustDomain.h @@ -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; diff --git a/security/certverifier/NSSCertDBTrustDomain.cpp b/security/certverifier/NSSCertDBTrustDomain.cpp index 794c6e2a03..83f312e5b3 100644 --- a/security/certverifier/NSSCertDBTrustDomain.cpp +++ b/security/certverifier/NSSCertDBTrustDomain.cpp @@ -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) diff --git a/security/certverifier/NSSCertDBTrustDomain.h b/security/certverifier/NSSCertDBTrustDomain.h index f380cc3f79..9dabaf6bfa 100644 --- a/security/certverifier/NSSCertDBTrustDomain.h +++ b/security/certverifier/NSSCertDBTrustDomain.h @@ -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; diff --git a/security/manager/locales/en-US/chrome/pipnss/nsserrors.properties b/security/manager/locales/en-US/chrome/pipnss/nsserrors.properties index 6e8f40731d..4fef9371d9 100644 --- a/security/manager/locales/en-US/chrome/pipnss/nsserrors.properties +++ b/security/manager/locales/en-US/chrome/pipnss/nsserrors.properties @@ -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. diff --git a/security/pkix/include/pkix/Result.h b/security/pkix/include/pkix/Result.h index f78169bf42..ffbda3a17f 100644 --- a/security/pkix/include/pkix/Result.h +++ b/security/pkix/include/pkix/Result.h @@ -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, \ diff --git a/security/pkix/include/pkix/pkixnss.h b/security/pkix/include/pkix/pkixnss.h index d951c0fbba..6d4f4c85e0 100644 --- a/security/pkix/include/pkix/pkixnss.h +++ b/security/pkix/include/pkix/pkixnss.h @@ -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(); diff --git a/security/pkix/include/pkix/pkixtypes.h b/security/pkix/include/pkix/pkixtypes.h index 916a55e9c4..97d1aef9f4 100644 --- a/security/pkix/include/pkix/pkixtypes.h +++ b/security/pkix/include/pkix/pkixtypes.h @@ -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, diff --git a/security/pkix/lib/pkixcert.cpp b/security/pkix/lib/pkixcert.cpp index 4cd33a337f..8e7be1fe45 100644 --- a/security/pkix/lib/pkixcert.cpp +++ b/security/pkix/lib/pkixcert.cpp @@ -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; diff --git a/security/pkix/lib/pkixcheck.cpp b/security/pkix/lib/pkixcheck.cpp index eea43a595c..dd70f0317a 100644 --- a/security/pkix/lib/pkixcheck.cpp +++ b/security/pkix/lib/pkixcheck.cpp @@ -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()); diff --git a/security/pkix/lib/pkixder.cpp b/security/pkix/lib/pkixder.cpp index b865dc5aa5..4fe3091c0c 100644 --- a/security/pkix/lib/pkixder.cpp +++ b/security/pkix/lib/pkixder.cpp @@ -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)) { diff --git a/security/pkix/lib/pkixnss.cpp b/security/pkix/lib/pkixnss.cpp index 04cc020523..2b8a30004f 100644 --- a/security/pkix/lib/pkixnss.cpp +++ b/security/pkix/lib/pkixnss.cpp @@ -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. diff --git a/security/pkix/lib/pkixutil.h b/security/pkix/lib/pkixutil.h index cc19582cf9..9179cedc2d 100644 --- a/security/pkix/lib/pkixutil.h +++ b/security/pkix/lib/pkixutil.h @@ -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 { diff --git a/security/pkix/test/gtest/moz.build b/security/pkix/test/gtest/moz.build index b0069b7af9..51952fb6df 100644 --- a/security/pkix/test/gtest/moz.build +++ b/security/pkix/test/gtest/moz.build @@ -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. diff --git a/security/pkix/test/gtest/pkixbuild_tests.cpp b/security/pkix/test/gtest/pkixbuild_tests.cpp index c2e0ead8b2..15f2c4c606 100644 --- a/security/pkix/test/gtest/pkixbuild_tests.cpp +++ b/security/pkix/test/gtest/pkixbuild_tests.cpp @@ -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 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; diff --git a/security/pkix/test/gtest/pkixcert_extension_tests.cpp b/security/pkix/test/gtest/pkixcert_extension_tests.cpp index 8d375120d3..62727a10df 100644 --- a/security/pkix/test/gtest/pkixcert_extension_tests.cpp +++ b/security/pkix/test/gtest/pkixcert_extension_tests.cpp @@ -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 diff --git a/security/pkix/test/gtest/pkixcert_signature_algorithm_tests.cpp b/security/pkix/test/gtest/pkixcert_signature_algorithm_tests.cpp index d11f23cabc..af622c3c33 100644 --- a/security/pkix/test/gtest/pkixcert_signature_algorithm_tests.cpp +++ b/security/pkix/test/gtest/pkixcert_signature_algorithm_tests.cpp @@ -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; diff --git a/security/pkix/test/gtest/pkixcheck_CheckKeyUsage_tests.cpp b/security/pkix/test/gtest/pkixcheck_CheckKeyUsage_tests.cpp index 54b4cd9e60..136f8719a8 100644 --- a/security/pkix/test/gtest/pkixcheck_CheckKeyUsage_tests.cpp +++ b/security/pkix/test/gtest/pkixcheck_CheckKeyUsage_tests.cpp @@ -23,8 +23,6 @@ */ #include "pkixgtest.h" -#include "pkix/pkixtypes.h" -#include "pkixtestutil.h" using namespace mozilla::pkix; using namespace mozilla::pkix::test; diff --git a/security/pkix/test/gtest/pkixcheck_CheckSignatureAlgorithm_tests.cpp b/security/pkix/test/gtest/pkixcheck_CheckSignatureAlgorithm_tests.cpp new file mode 100644 index 0000000000..a8983835aa --- /dev/null +++ b/security/pkix/test/gtest/pkixcheck_CheckSignatureAlgorithm_tests.cpp @@ -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 +{ +}; + +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); +} diff --git a/security/pkix/test/gtest/pkixcheck_CheckValidity_tests.cpp b/security/pkix/test/gtest/pkixcheck_CheckValidity_tests.cpp index d176ca3641..72f69fa863 100644 --- a/security/pkix/test/gtest/pkixcheck_CheckValidity_tests.cpp +++ b/security/pkix/test/gtest/pkixcheck_CheckValidity_tests.cpp @@ -23,8 +23,6 @@ */ #include "pkixgtest.h" -#include "pkix/pkixtypes.h" -#include "pkixtestutil.h" using namespace mozilla::pkix; using namespace mozilla::pkix::test; diff --git a/security/pkix/test/gtest/pkixder_universal_types_tests.cpp b/security/pkix/test/gtest/pkixder_universal_types_tests.cpp index 5207b05f02..e54a186ff2 100644 --- a/security/pkix/test/gtest/pkixder_universal_types_tests.cpp +++ b/security/pkix/test/gtest/pkixder_universal_types_tests.cpp @@ -23,12 +23,11 @@ */ #include +#include #include -#include "pkixgtest.h" #include "pkixder.h" -#include "pkixtestutil.h" -#include "stdint.h" +#include "pkixgtest.h" using namespace mozilla::pkix; using namespace mozilla::pkix::der; diff --git a/security/pkix/test/gtest/pkixgtest.h b/security/pkix/test/gtest/pkixgtest.h index 84a7b08503..faef136284 100644 --- a/security/pkix/test/gtest/pkixgtest.h +++ b/security/pkix/test/gtest/pkixgtest.h @@ -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 diff --git a/security/pkix/test/gtest/pkixnames_tests.cpp b/security/pkix/test/gtest/pkixnames_tests.cpp index 30a656539b..7662b4e1a5 100644 --- a/security/pkix/test/gtest/pkixnames_tests.cpp +++ b/security/pkix/test/gtest/pkixnames_tests.cpp @@ -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 { diff --git a/security/pkix/test/gtest/pkixocsp_CreateEncodedOCSPRequest_tests.cpp b/security/pkix/test/gtest/pkixocsp_CreateEncodedOCSPRequest_tests.cpp index 6f31d21da8..81a578edfe 100644 --- a/security/pkix/test/gtest/pkixocsp_CreateEncodedOCSPRequest_tests.cpp +++ b/security/pkix/test/gtest/pkixocsp_CreateEncodedOCSPRequest_tests.cpp @@ -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; } }; diff --git a/security/pkix/test/gtest/pkixocsp_VerifyEncodedOCSPResponse.cpp b/security/pkix/test/gtest/pkixocsp_VerifyEncodedOCSPResponse.cpp index d25e54d635..ac10090b48 100644 --- a/security/pkix/test/gtest/pkixocsp_VerifyEncodedOCSPResponse.cpp +++ b/security/pkix/test/gtest/pkixocsp_VerifyEncodedOCSPResponse.cpp @@ -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 { diff --git a/toolkit/modules/Troubleshoot.jsm b/toolkit/modules/Troubleshoot.jsm index 76971a7403..06747b0199 100644 --- a/toolkit/modules/Troubleshoot.jsm +++ b/toolkit/modules/Troubleshoot.jsm @@ -24,6 +24,7 @@ catch (e) { // under the "accessibility.*" branch. const PREFS_WHITELIST = [ "accessibility.", + "apz.", "browser.cache.", "browser.display.", "browser.download.folderList", diff --git a/toolkit/mozapps/update/nsUpdateService.js b/toolkit/mozapps/update/nsUpdateService.js index b310c0a5b1..e30afc09b8 100644 --- a/toolkit/mozapps/update/nsUpdateService.js +++ b/toolkit/mozapps/update/nsUpdateService.js @@ -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; } diff --git a/toolkit/mozapps/update/tests/chrome/test_9999_cleanup.xul b/toolkit/mozapps/update/tests/chrome/test_9999_cleanup.xul index c915b08a94..430d0799af 100644 --- a/toolkit/mozapps/update/tests/chrome/test_9999_cleanup.xul +++ b/toolkit/mozapps/update/tests/chrome/test_9999_cleanup.xul @@ -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); diff --git a/toolkit/mozapps/update/tests/chrome/utils.js b/toolkit/mozapps/update/tests/chrome/utils.js index 3f5848bdd8..40a94f6d66 100644 --- a/toolkit/mozapps/update/tests/chrome/utils.js +++ b/toolkit/mozapps/update/tests/chrome/utils.js @@ -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); } } } diff --git a/toolkit/mozapps/update/tests/shared.js b/toolkit/mozapps/update/tests/shared.js index d70179654a..86aa7e91c5 100644 --- a/toolkit/mozapps/update/tests/shared.js +++ b/toolkit/mozapps/update/tests/shared.js @@ -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); } /** diff --git a/toolkit/mozapps/update/tests/unit_aus_update/canCheckForAndCanApplyUpdates.js b/toolkit/mozapps/update/tests/unit_aus_update/canCheckForAndCanApplyUpdates.js index e30c2487da..191a18a03b 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/canCheckForAndCanApplyUpdates.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/canCheckForAndCanApplyUpdates.js @@ -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; } diff --git a/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForDifferentChannel.js b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForDifferentChannel.js index c31ce5a602..1401336418 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForDifferentChannel.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForDifferentChannel.js @@ -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("")); diff --git a/toolkit/mozapps/update/tests/unit_aus_update/downloadFileTooBig_gonk.js b/toolkit/mozapps/update/tests/unit_aus_update/downloadFileTooBig_gonk.js index f30f3eee54..0c7c3ed723 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/downloadFileTooBig_gonk.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadFileTooBig_gonk.js @@ -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 = { diff --git a/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedRecovery.js b/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedRecovery.js index 7f2d146243..982ae0a0dc 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedRecovery.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedRecovery.js @@ -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 diff --git a/toolkit/mozapps/update/tests/unit_aus_update/head_update.js b/toolkit/mozapps/update/tests/unit_aus_update/head_update.js index 624932f30d..20666ab700 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/head_update.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/head_update.js @@ -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", ""); } diff --git a/toolkit/mozapps/update/tests/unit_aus_update/uiUnsupportedAlreadyNotified.js b/toolkit/mozapps/update/tests/unit_aus_update/uiUnsupportedAlreadyNotified.js index 8153640220..0b3979ab88 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/uiUnsupportedAlreadyNotified.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/uiUnsupportedAlreadyNotified.js @@ -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}"), diff --git a/toolkit/mozapps/update/tests/unit_timermanager/consumerNotifications.js b/toolkit/mozapps/update/tests/unit_timermanager/consumerNotifications.js index 4e7fa3f2ed..9ab331f7de 100644 --- a/toolkit/mozapps/update/tests/unit_timermanager/consumerNotifications.js +++ b/toolkit/mozapps/update/tests/unit_timermanager/consumerNotifications.js @@ -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; } };