Wed, 31 Dec 2014 07:16:47 +0100
Revert simplistic fix pending revisit of Mozilla integration attempt.
michael@0 | 1 | function px_to_num(str) |
michael@0 | 2 | { |
michael@0 | 3 | return Number(String(str).match(/^([\d.]+)px$/)[1]); |
michael@0 | 4 | } |
michael@0 | 5 | |
michael@0 | 6 | function bezier(x1, y1, x2, y2) { |
michael@0 | 7 | // Cubic bezier with control points (0, 0), (x1, y1), (x2, y2), and (1, 1). |
michael@0 | 8 | function x_for_t(t) { |
michael@0 | 9 | var omt = 1-t; |
michael@0 | 10 | return 3 * omt * omt * t * x1 + 3 * omt * t * t * x2 + t * t * t; |
michael@0 | 11 | } |
michael@0 | 12 | function y_for_t(t) { |
michael@0 | 13 | var omt = 1-t; |
michael@0 | 14 | return 3 * omt * omt * t * y1 + 3 * omt * t * t * y2 + t * t * t; |
michael@0 | 15 | } |
michael@0 | 16 | function t_for_x(x) { |
michael@0 | 17 | // Binary subdivision. |
michael@0 | 18 | var mint = 0, maxt = 1; |
michael@0 | 19 | for (var i = 0; i < 30; ++i) { |
michael@0 | 20 | var guesst = (mint + maxt) / 2; |
michael@0 | 21 | var guessx = x_for_t(guesst); |
michael@0 | 22 | if (x < guessx) |
michael@0 | 23 | maxt = guesst; |
michael@0 | 24 | else |
michael@0 | 25 | mint = guesst; |
michael@0 | 26 | } |
michael@0 | 27 | return (mint + maxt) / 2; |
michael@0 | 28 | } |
michael@0 | 29 | return function bezier_closure(x) { |
michael@0 | 30 | if (x == 0) return 0; |
michael@0 | 31 | if (x == 1) return 1; |
michael@0 | 32 | return y_for_t(t_for_x(x)); |
michael@0 | 33 | } |
michael@0 | 34 | } |
michael@0 | 35 | |
michael@0 | 36 | function step_end(nsteps) { |
michael@0 | 37 | return function step_end_closure(x) { |
michael@0 | 38 | return Math.floor(x * nsteps) / nsteps; |
michael@0 | 39 | } |
michael@0 | 40 | } |
michael@0 | 41 | |
michael@0 | 42 | function step_start(nsteps) { |
michael@0 | 43 | var stepend = step_end(nsteps); |
michael@0 | 44 | return function step_start_closure(x) { |
michael@0 | 45 | return 1.0 - stepend(1.0 - x); |
michael@0 | 46 | } |
michael@0 | 47 | } |
michael@0 | 48 | |
michael@0 | 49 | var gTF = { |
michael@0 | 50 | "ease": bezier(0.25, 0.1, 0.25, 1), |
michael@0 | 51 | "linear": function(x) { return x; }, |
michael@0 | 52 | "ease_in": bezier(0.42, 0, 1, 1), |
michael@0 | 53 | "ease_out": bezier(0, 0, 0.58, 1), |
michael@0 | 54 | "ease_in_out": bezier(0.42, 0, 0.58, 1), |
michael@0 | 55 | "step_start": step_start(1), |
michael@0 | 56 | "step_end": step_end(1), |
michael@0 | 57 | }; |
michael@0 | 58 | |
michael@0 | 59 | function is_approx(float1, float2, error, desc) { |
michael@0 | 60 | ok(Math.abs(float1 - float2) < error, |
michael@0 | 61 | desc + ": " + float1 + " and " + float2 + " should be within " + error); |
michael@0 | 62 | } |
michael@0 | 63 | |
michael@0 | 64 | // Checks if off-main thread animation (OMTA) is available, and if it is, runs |
michael@0 | 65 | // the provided callback function. If OMTA is not available or is not |
michael@0 | 66 | // functioning correctly, the second callback, aOnSkip, is run instead. |
michael@0 | 67 | // |
michael@0 | 68 | // This function also does an internal test to verify that OMTA is working at |
michael@0 | 69 | // all so that if OMTA is not functioning correctly when it is expected to |
michael@0 | 70 | // function only a single failure is produced. |
michael@0 | 71 | // |
michael@0 | 72 | // Since this function relies on various asynchronous operations, the caller is |
michael@0 | 73 | // responsible for calling SimpleTest.waitForExplicitFinish() before calling |
michael@0 | 74 | // this and SimpleTest.finish() within aTestFunction and aOnSkip. |
michael@0 | 75 | function runOMTATest(aTestFunction, aOnSkip) { |
michael@0 | 76 | const OMTAPrefKey = "layers.offmainthreadcomposition.async-animations"; |
michael@0 | 77 | var utils = SpecialPowers.DOMWindowUtils; |
michael@0 | 78 | var expectOMTA = utils.layerManagerRemote && |
michael@0 | 79 | // ^ Off-main thread animation cannot be used if off-main |
michael@0 | 80 | // thread composition (OMTC) is not available |
michael@0 | 81 | SpecialPowers.getBoolPref(OMTAPrefKey); |
michael@0 | 82 | |
michael@0 | 83 | isOMTAWorking().then(function(isWorking) { |
michael@0 | 84 | if (expectOMTA) { |
michael@0 | 85 | if (isWorking) { |
michael@0 | 86 | aTestFunction(); |
michael@0 | 87 | } else { |
michael@0 | 88 | // We only call this when we know it will fail as otherwise in the |
michael@0 | 89 | // regular success case we will end up inflating the "passed tests" |
michael@0 | 90 | // count by 1 |
michael@0 | 91 | ok(isWorking, "OMTA is working as expected"); |
michael@0 | 92 | aOnSkip(); |
michael@0 | 93 | } |
michael@0 | 94 | } else { |
michael@0 | 95 | todo(isWorking, "OMTA is working"); |
michael@0 | 96 | aOnSkip(); |
michael@0 | 97 | } |
michael@0 | 98 | }).catch(function(err) { |
michael@0 | 99 | ok(false, err); |
michael@0 | 100 | aOnSkip(); |
michael@0 | 101 | }); |
michael@0 | 102 | |
michael@0 | 103 | function isOMTAWorking() { |
michael@0 | 104 | // Create keyframes rule |
michael@0 | 105 | const animationName = "a6ce3091ed85"; // Random name to avoid clashes |
michael@0 | 106 | var ruleText = "@keyframes " + animationName + |
michael@0 | 107 | " { from { opacity: 0.5 } to { opacity 0.5 } }"; |
michael@0 | 108 | var style = document.createElement("style"); |
michael@0 | 109 | style.appendChild(document.createTextNode(ruleText)); |
michael@0 | 110 | document.head.appendChild(style); |
michael@0 | 111 | |
michael@0 | 112 | // Create animation target |
michael@0 | 113 | var div = document.createElement("div"); |
michael@0 | 114 | document.body.appendChild(div); |
michael@0 | 115 | |
michael@0 | 116 | // Give the target geometry so it is eligible for layerization |
michael@0 | 117 | div.style.width = "100px"; |
michael@0 | 118 | div.style.height = "100px"; |
michael@0 | 119 | div.style.backgroundColor = "white"; |
michael@0 | 120 | |
michael@0 | 121 | // Common clean up code |
michael@0 | 122 | var cleanUp = function() { |
michael@0 | 123 | div.parentNode.removeChild(div); |
michael@0 | 124 | style.parentNode.removeChild(style); |
michael@0 | 125 | if (utils.isTestControllingRefreshes) { |
michael@0 | 126 | utils.restoreNormalRefresh(); |
michael@0 | 127 | } |
michael@0 | 128 | }; |
michael@0 | 129 | |
michael@0 | 130 | return waitForDocumentLoad() |
michael@0 | 131 | .then(loadPaintListener) |
michael@0 | 132 | .then(function() { |
michael@0 | 133 | // Put refresh driver under test control and trigger animation |
michael@0 | 134 | utils.advanceTimeAndRefresh(0); |
michael@0 | 135 | div.style.animation = animationName + " 10s"; |
michael@0 | 136 | |
michael@0 | 137 | // Trigger style flush |
michael@0 | 138 | div.clientTop; |
michael@0 | 139 | return waitForPaints(); |
michael@0 | 140 | }).then(function() { |
michael@0 | 141 | var opacity = utils.getOMTAStyle(div, "opacity"); |
michael@0 | 142 | cleanUp(); |
michael@0 | 143 | return Promise.resolve(opacity == 0.5); |
michael@0 | 144 | }).catch(function(err) { |
michael@0 | 145 | cleanUp(); |
michael@0 | 146 | return Promise.reject(err); |
michael@0 | 147 | }); |
michael@0 | 148 | } |
michael@0 | 149 | |
michael@0 | 150 | function waitForDocumentLoad() { |
michael@0 | 151 | return new Promise(function(resolve, reject) { |
michael@0 | 152 | if (document.readyState === "complete") { |
michael@0 | 153 | resolve(); |
michael@0 | 154 | } else { |
michael@0 | 155 | window.addEventListener("load", resolve); |
michael@0 | 156 | } |
michael@0 | 157 | }); |
michael@0 | 158 | } |
michael@0 | 159 | |
michael@0 | 160 | function waitForPaints() { |
michael@0 | 161 | return new Promise(function(resolve, reject) { |
michael@0 | 162 | waitForAllPaintsFlushed(resolve); |
michael@0 | 163 | }); |
michael@0 | 164 | } |
michael@0 | 165 | |
michael@0 | 166 | function loadPaintListener() { |
michael@0 | 167 | return new Promise(function(resolve, reject) { |
michael@0 | 168 | if (typeof(window.waitForAllPaints) !== "function") { |
michael@0 | 169 | var script = document.createElement("script"); |
michael@0 | 170 | script.onload = resolve; |
michael@0 | 171 | script.onerror = function() { |
michael@0 | 172 | reject(new Error("Failed to load paint listener")); |
michael@0 | 173 | }; |
michael@0 | 174 | script.src = "/tests/SimpleTest/paint_listener.js"; |
michael@0 | 175 | var firstScript = document.scripts[0]; |
michael@0 | 176 | firstScript.parentNode.insertBefore(script, firstScript); |
michael@0 | 177 | } else { |
michael@0 | 178 | resolve(); |
michael@0 | 179 | } |
michael@0 | 180 | }); |
michael@0 | 181 | } |
michael@0 | 182 | } |