From 915ac20c76a1f9f220232203ea871bdd14aee9a1 Mon Sep 17 00:00:00 2001 From: Daniel Andersson Date: Mon, 2 Oct 2017 17:03:03 -0700 Subject: [PATCH] Avoid eval in buildStyleInterpolator Reviewed By: vjeux Differential Revision: D5950405 fbshipit-source-id: ee794317f820e8fbb87752b88539171115a8e00e --- Libraries/Utilities/buildStyleInterpolator.js | 647 ++++-------------- 1 file changed, 128 insertions(+), 519 deletions(-) diff --git a/Libraries/Utilities/buildStyleInterpolator.js b/Libraries/Utilities/buildStyleInterpolator.js index 06dee1898..41d65e1bf 100644 --- a/Libraries/Utilities/buildStyleInterpolator.js +++ b/Libraries/Utilities/buildStyleInterpolator.js @@ -9,547 +9,137 @@ * @providesModule buildStyleInterpolator */ -/** - * Cannot "use strict" because we must use eval in this file. - */ -/* eslint-disable global-strict */ +'use strict'; var keyOf = require('fbjs/lib/keyOf'); var X_DIM = keyOf({x: null}); var Y_DIM = keyOf({y: null}); var Z_DIM = keyOf({z: null}); -var W_DIM = keyOf({w: null}); - -var TRANSFORM_ROTATE_NAME = keyOf({transformRotateRadians: null}); - -var ShouldAllocateReusableOperationVars = { - transformRotateRadians: true, - transformScale: true, - transformTranslate: true, -}; var InitialOperationField = { - transformRotateRadians: [0, 0, 0, 1], transformTranslate: [0, 0, 0], transformScale: [1, 1, 1], }; - -/** - * Creates a highly specialized animation function that may be evaluated every - * frame. For example: - * - * var ToTheLeft = { - * opacity: { - * from: 1, - * to: 0.7, - * min: 0, - * max: 1, - * type: 'linear', - * extrapolate: false, - * round: 100, - * }, - * left: { - * from: 0, - * to: -SCREEN_WIDTH * 0.3, - * min: 0, - * max: 1, - * type: 'linear', - * extrapolate: true, - * round: PixelRatio.get(), - * }, - * }; - * - * var toTheLeft = buildStyleInterpolator(ToTheLeft); - * - * Would returns a specialized function of the form: - * - * function(result, value) { - * var didChange = false; - * var nextScalarVal; - * var ratio; - * ratio = (value - 0) / 1; - * ratio = ratio > 1 ? 1 : (ratio < 0 ? 0 : ratio); - * nextScalarVal = Math.round(100 * (1 * (1 - ratio) + 0.7 * ratio)) / 100; - * if (!didChange) { - * var prevVal = result.opacity; - * result.opacity = nextScalarVal; - * didChange = didChange || (nextScalarVal !== prevVal); - * } else { - * result.opacity = nextScalarVal; - * } - * ratio = (value - 0) / 1; - * nextScalarVal = Math.round(2 * (0 * (1 - ratio) + -30 * ratio)) / 2; - * if (!didChange) { - * var prevVal = result.left; - * result.left = nextScalarVal; - * didChange = didChange || (nextScalarVal !== prevVal); - * } else { - * result.left = nextScalarVal; - * } - * return didChange; - * } - */ - -var ARGUMENT_NAMES_RE = /([^\s,]+)/g; -/** - * This is obviously a huge hack. Proper tooling would allow actual inlining. - * This only works in a few limited cases (where there is no function return - * value, and the function operates mutatively on parameters). - * - * Example: - * - * - * var inlineMe(a, b) { - * a = b + b; - * }; - * - * inline(inlineMe, ['hi', 'bye']); // "hi = bye + bye;" - * - * @param {string} fnStr Source of any simple function who's arguments can be - * replaced via a regex. - * @param {array} replaceWithArgs Corresponding names of variables - * within an environment, to replace `func` args with. - * @return {string} Resulting function body string. - */ -var inline = function(fnStr, replaceWithArgs) { - var parameterNames = fnStr.slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')')) - .match(ARGUMENT_NAMES_RE) || - []; - var replaceRegexStr = parameterNames.map(function(paramName) { - return '\\b' + paramName + '\\b'; - }).join('|'); - var replaceRegex = new RegExp(replaceRegexStr, 'g'); - var fnBody = fnStr.substring(fnStr.indexOf('{') + 1, fnStr.lastIndexOf('}')); - var newFnBody = fnBody.replace(replaceRegex, function(parameterName) { - var indexInParameterNames = parameterNames.indexOf(parameterName); - var replacementName = replaceWithArgs[indexInParameterNames]; - return replacementName; - }); - return newFnBody.split('\n'); +var InterpolateMatrix = { + transformScale: function(mat, x, y, z) { + mat[0] = mat[0] * x; + mat[1] = mat[1] * x; + mat[2] = mat[2] * x; + mat[3] = mat[3] * x; + mat[4] = mat[4] * y; + mat[5] = mat[5] * y; + mat[6] = mat[6] * y; + mat[7] = mat[7] * y; + mat[8] = mat[8] * z; + mat[9] = mat[9] * z; + mat[10] = mat[10] * z; + mat[11] = mat[11] * z; + }, + transformTranslate: function(mat, x, y, z) { + mat[12] = mat[0] * x + mat[4] * y + mat[8] * z + mat[12]; + mat[13] = mat[1] * x + mat[5] * y + mat[9] * z + mat[13]; + mat[14] = mat[2] * x + mat[6] * y + mat[10] * z + mat[14]; + mat[15] = mat[3] * x + mat[7] * y + mat[11] * z + mat[15]; + } }; -/** - * Simply a convenient way to inline functions using the inline function. - */ -var MatrixOps = { - unroll: `function(matVar, m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15) { - m0 = matVar[0]; - m1 = matVar[1]; - m2 = matVar[2]; - m3 = matVar[3]; - m4 = matVar[4]; - m5 = matVar[5]; - m6 = matVar[6]; - m7 = matVar[7]; - m8 = matVar[8]; - m9 = matVar[9]; - m10 = matVar[10]; - m11 = matVar[11]; - m12 = matVar[12]; - m13 = matVar[13]; - m14 = matVar[14]; - m15 = matVar[15]; - }`, - - matrixDiffers: `function(retVar, matVar, m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15) { - retVar = retVar || - m0 !== matVar[0] || - m1 !== matVar[1] || - m2 !== matVar[2] || - m3 !== matVar[3] || - m4 !== matVar[4] || - m5 !== matVar[5] || - m6 !== matVar[6] || - m7 !== matVar[7] || - m8 !== matVar[8] || - m9 !== matVar[9] || - m10 !== matVar[10] || - m11 !== matVar[11] || - m12 !== matVar[12] || - m13 !== matVar[13] || - m14 !== matVar[14] || - m15 !== matVar[15]; - }`, - - transformScale: `function(matVar, opVar) { - // Scaling matVar by opVar - var x = opVar[0]; - var y = opVar[1]; - var z = opVar[2]; - matVar[0] = matVar[0] * x; - matVar[1] = matVar[1] * x; - matVar[2] = matVar[2] * x; - matVar[3] = matVar[3] * x; - matVar[4] = matVar[4] * y; - matVar[5] = matVar[5] * y; - matVar[6] = matVar[6] * y; - matVar[7] = matVar[7] * y; - matVar[8] = matVar[8] * z; - matVar[9] = matVar[9] * z; - matVar[10] = matVar[10] * z; - matVar[11] = matVar[11] * z; - matVar[12] = matVar[12]; - matVar[13] = matVar[13]; - matVar[14] = matVar[14]; - matVar[15] = matVar[15]; - }`, - - /** - * All of these matrix transforms are not general purpose utilities, and are - * only suitable for being inlined for the use of building up interpolators. - */ - transformTranslate: `function(matVar, opVar) { - // Translating matVar by opVar - var x = opVar[0]; - var y = opVar[1]; - var z = opVar[2]; - matVar[12] = matVar[0] * x + matVar[4] * y + matVar[8] * z + matVar[12]; - matVar[13] = matVar[1] * x + matVar[5] * y + matVar[9] * z + matVar[13]; - matVar[14] = matVar[2] * x + matVar[6] * y + matVar[10] * z + matVar[14]; - matVar[15] = matVar[3] * x + matVar[7] * y + matVar[11] * z + matVar[15]; - }`, - - /** - * @param {array} matVar Both the input, and the output matrix. - * @param {quaternion specification} q Four element array describing rotation. - */ - transformRotateRadians: `function(matVar, q) { - // Rotating matVar by q - var xQuat = q[0], yQuat = q[1], zQuat = q[2], wQuat = q[3]; - var x2Quat = xQuat + xQuat; - var y2Quat = yQuat + yQuat; - var z2Quat = zQuat + zQuat; - var xxQuat = xQuat * x2Quat; - var xyQuat = xQuat * y2Quat; - var xzQuat = xQuat * z2Quat; - var yyQuat = yQuat * y2Quat; - var yzQuat = yQuat * z2Quat; - var zzQuat = zQuat * z2Quat; - var wxQuat = wQuat * x2Quat; - var wyQuat = wQuat * y2Quat; - var wzQuat = wQuat * z2Quat; - // Step 1: Inlines the construction of a quaternion matrix ('quatMat') - var quatMat0 = 1 - (yyQuat + zzQuat); - var quatMat1 = xyQuat + wzQuat; - var quatMat2 = xzQuat - wyQuat; - var quatMat4 = xyQuat - wzQuat; - var quatMat5 = 1 - (xxQuat + zzQuat); - var quatMat6 = yzQuat + wxQuat; - var quatMat8 = xzQuat + wyQuat; - var quatMat9 = yzQuat - wxQuat; - var quatMat10 = 1 - (xxQuat + yyQuat); - // quatMat3/7/11/12/13/14 = 0, quatMat15 = 1 - - // Step 2: Inlines multiplication, takes advantage of constant quatMat cells - var a00 = matVar[0]; - var a01 = matVar[1]; - var a02 = matVar[2]; - var a03 = matVar[3]; - var a10 = matVar[4]; - var a11 = matVar[5]; - var a12 = matVar[6]; - var a13 = matVar[7]; - var a20 = matVar[8]; - var a21 = matVar[9]; - var a22 = matVar[10]; - var a23 = matVar[11]; - - var b0 = quatMat0, b1 = quatMat1, b2 = quatMat2; - matVar[0] = b0 * a00 + b1 * a10 + b2 * a20; - matVar[1] = b0 * a01 + b1 * a11 + b2 * a21; - matVar[2] = b0 * a02 + b1 * a12 + b2 * a22; - matVar[3] = b0 * a03 + b1 * a13 + b2 * a23; - b0 = quatMat4; b1 = quatMat5; b2 = quatMat6; - matVar[4] = b0 * a00 + b1 * a10 + b2 * a20; - matVar[5] = b0 * a01 + b1 * a11 + b2 * a21; - matVar[6] = b0 * a02 + b1 * a12 + b2 * a22; - matVar[7] = b0 * a03 + b1 * a13 + b2 * a23; - b0 = quatMat8; b1 = quatMat9; b2 = quatMat10; - matVar[8] = b0 * a00 + b1 * a10 + b2 * a20; - matVar[9] = b0 * a01 + b1 * a11 + b2 * a21; - matVar[10] = b0 * a02 + b1 * a12 + b2 * a22; - matVar[11] = b0 * a03 + b1 * a13 + b2 * a23; - }` -}; - -// Optimized version of general operation applications that can be used when -// the target matrix is known to be the identity matrix. -var MatrixOpsInitial = { - transformScale: `function(matVar, opVar) { - // Scaling matVar known to be identity by opVar - matVar[0] = opVar[0]; - matVar[1] = 0; - matVar[2] = 0; - matVar[3] = 0; - matVar[4] = 0; - matVar[5] = opVar[1]; - matVar[6] = 0; - matVar[7] = 0; - matVar[8] = 0; - matVar[9] = 0; - matVar[10] = opVar[2]; - matVar[11] = 0; - matVar[12] = 0; - matVar[13] = 0; - matVar[14] = 0; - matVar[15] = 1; - }`, - - transformTranslate: `function(matVar, opVar) { - // Translating matVar known to be identity by opVar; - matVar[0] = 1; - matVar[1] = 0; - matVar[2] = 0; - matVar[3] = 0; - matVar[4] = 0; - matVar[5] = 1; - matVar[6] = 0; - matVar[7] = 0; - matVar[8] = 0; - matVar[9] = 0; - matVar[10] = 1; - matVar[11] = 0; - matVar[12] = opVar[0]; - matVar[13] = opVar[1]; - matVar[14] = opVar[2]; - matVar[15] = 1; - }`, - - /** - * @param {array} matVar Both the input, and the output matrix - assumed to be - * identity. - * @param {quaternion specification} q Four element array describing rotation. - */ - transformRotateRadians: `function(matVar, q) { - - // Rotating matVar which is known to be identity by q - var xQuat = q[0], yQuat = q[1], zQuat = q[2], wQuat = q[3]; - var x2Quat = xQuat + xQuat; - var y2Quat = yQuat + yQuat; - var z2Quat = zQuat + zQuat; - var xxQuat = xQuat * x2Quat; - var xyQuat = xQuat * y2Quat; - var xzQuat = xQuat * z2Quat; - var yyQuat = yQuat * y2Quat; - var yzQuat = yQuat * z2Quat; - var zzQuat = zQuat * z2Quat; - var wxQuat = wQuat * x2Quat; - var wyQuat = wQuat * y2Quat; - var wzQuat = wQuat * z2Quat; - // Step 1: Inlines the construction of a quaternion matrix ('quatMat') - var quatMat0 = 1 - (yyQuat + zzQuat); - var quatMat1 = xyQuat + wzQuat; - var quatMat2 = xzQuat - wyQuat; - var quatMat4 = xyQuat - wzQuat; - var quatMat5 = 1 - (xxQuat + zzQuat); - var quatMat6 = yzQuat + wxQuat; - var quatMat8 = xzQuat + wyQuat; - var quatMat9 = yzQuat - wxQuat; - var quatMat10 = 1 - (xxQuat + yyQuat); - // quatMat3/7/11/12/13/14 = 0, quatMat15 = 1 - - // Step 2: Inlines the multiplication with identity matrix. - var b0 = quatMat0, b1 = quatMat1, b2 = quatMat2; - matVar[0] = b0; - matVar[1] = b1; - matVar[2] = b2; - matVar[3] = 0; - b0 = quatMat4; b1 = quatMat5; b2 = quatMat6; - matVar[4] = b0; - matVar[5] = b1; - matVar[6] = b2; - matVar[7] = 0; - b0 = quatMat8; b1 = quatMat9; b2 = quatMat10; - matVar[8] = b0; - matVar[9] = b1; - matVar[10] = b2; - matVar[11] = 0; - matVar[12] = 0; - matVar[13] = 0; - matVar[14] = 0; - matVar[15] = 1; - }` -}; - - -var setNextValAndDetectChange = function(name, tmpVarName) { - return ( - ' if (!didChange) {\n' + - ' var prevVal = result.' + name + ';\n' + - ' result.' + name + ' = ' + tmpVarName + ';\n' + - ' didChange = didChange || (' + tmpVarName + ' !== prevVal);\n' + - ' } else {\n' + - ' result.' + name + ' = ' + tmpVarName + ';\n' + - ' }\n' - ); -}; - -var computeNextValLinear = function(anim, from, to, tmpVarName) { +var computeNextValLinear = function(anim, from, to, value) { var hasRoundRatio = 'round' in anim; var roundRatio = anim.round; - var fn = ' ratio = (value - ' + anim.min + ') / ' + (anim.max - anim.min) + ';\n'; + var ratio = (value - anim.min) / (anim.max - anim.min); if (!anim.extrapolate) { - fn += ' ratio = ratio > 1 ? 1 : (ratio < 0 ? 0 : ratio);\n'; + ratio = ratio > 1 ? 1 : (ratio < 0 ? 0 : ratio); } - - var roundOpen = (hasRoundRatio ? 'Math.round(' + roundRatio + ' * ' : '' ); - var roundClose = (hasRoundRatio ? ') / ' + roundRatio : '' ); - fn += - ' ' + tmpVarName + ' = ' + - roundOpen + - '(' + from + ' * (1 - ratio) + ' + to + ' * ratio)' + - roundClose + ';\n'; - return fn; -}; - -var computeNextValLinearScalar = function(anim) { - return computeNextValLinear(anim, anim.from, anim.to, 'nextScalarVal'); -}; - -var computeNextValConstant = function(anim) { - var constantExpression = JSON.stringify(anim.value); - return ' nextScalarVal = ' + constantExpression + ';\n'; -}; - -var computeNextValStep = function(anim) { - return ( - ' nextScalarVal = value >= ' + - (anim.threshold + ' ? ' + anim.to + ' : ' + anim.from) + ';\n' - ); -}; - -var computeNextValIdentity = function(anim) { - return ' nextScalarVal = value;\n'; -}; - -var operationVar = function(name) { - return name + 'ReuseOp'; -}; - -var createReusableOperationVars = function(anims) { - var ret = ''; - for (var name in anims) { - if (ShouldAllocateReusableOperationVars[name]) { - ret += 'var ' + operationVar(name) + ' = [];\n'; - } + var nextVal = from * (1 - ratio) + to * ratio; + if (hasRoundRatio) { + nextVal = Math.round(roundRatio * nextVal) / roundRatio; } - return ret; + return nextVal; }; -var newlines = function(statements) { - return '\n' + statements.join('\n') + '\n'; +var computeNextValLinearScalar = function(anim, value) { + return computeNextValLinear(anim, anim.from, anim.to, value); }; -/** - * @param {Animation} anim Configuration entry. - * @param {key} dimension Key to examine in `from`/`to`. - * @param {number} index Field in operationVar to set. - * @return {string} Code that sets the operation variable's field. - */ -var computeNextMatrixOperationField = function(anim, name, dimension, index) { - var fieldAccess = operationVar(name) + '[' + index + ']'; - if (anim.from[dimension] !== undefined && anim.to[dimension] !== undefined) { - return ' ' + anim.from[dimension] !== anim.to[dimension] ? - computeNextValLinear(anim, anim.from[dimension], anim.to[dimension], fieldAccess) : - fieldAccess + ' = ' + anim.from[dimension] + ';'; +var setNextValAndDetectChange = function(result, name, nextVal, didChange) { + if (!didChange) { + var prevVal = result[name]; + result[name] = nextVal; + didChange = didChange || (nextVal !== prevVal); } else { - return ' ' + fieldAccess + ' = ' + InitialOperationField[name][index] + ';'; + result[name] = nextVal; + } + return didChange; +}; + +var initIdentity = function(mat) { + mat[0] = 1; + mat[1] = 0; + mat[2] = 0; + mat[3] = 0; + mat[4] = 0; + mat[5] = 1; + mat[6] = 0; + mat[7] = 0; + mat[8] = 0; + mat[9] = 0; + mat[10] = 1; + mat[11] = 0; + mat[12] = 0; + mat[13] = 0; + mat[14] = 0; + mat[15] = 1; +}; + +var computeNextMatrixOperationField = function(anim, name, dim, index, value) { + if (anim.from[dim] !== undefined && anim.to[dim] !== undefined) { + return computeNextValLinear(anim, anim.from[dim], anim.to[dim], value); + } else { + return InitialOperationField[name][index]; } }; -var unrolledVars = []; -for (var varIndex = 0; varIndex < 16; varIndex++) { - unrolledVars.push('m' + varIndex); -} -var setNextMatrixAndDetectChange = function(orderedMatrixOperations) { - var fn = [ - ' var transform = result.transform !== undefined ? ' + - 'result.transform : (result.transform = [{ matrix: [] }]);' + - ' var transformMatrix = transform[0].matrix;' - ]; - fn.push.apply( - fn, - inline(MatrixOps.unroll, ['transformMatrix'].concat(unrolledVars)) - ); - for (var i = 0; i < orderedMatrixOperations.length; i++) { - var opName = orderedMatrixOperations[i]; - if (i === 0) { - fn.push.apply( - fn, - inline(MatrixOpsInitial[opName], ['transformMatrix', operationVar(opName)]) - ); - } else { - fn.push.apply( - fn, - inline(MatrixOps[opName], ['transformMatrix', operationVar(opName)]) - ); - } +var computeTransform = function(anim, name, value, result, + didChange, didMatrix) { + var transform = result.transform !== undefined ? + result.transform : (result.transform = [{ matrix: [] }]); + var mat = transform[0].matrix; + var m0 = mat[0]; + var m1 = mat[1]; + var m2 = mat[2]; + var m3 = mat[3]; + var m4 = mat[4]; + var m5 = mat[5]; + var m6 = mat[6]; + var m7 = mat[7]; + var m8 = mat[8]; + var m9 = mat[9]; + var m10 = mat[10]; + var m11 = mat[11]; + var m12 = mat[12]; + var m13 = mat[13]; + var m14 = mat[14]; + var m15 = mat[15]; + if (!didMatrix) { + initIdentity(mat); // This will be the first transform. } - fn.push.apply( - fn, - inline(MatrixOps.matrixDiffers, ['didChange', 'transformMatrix'].concat(unrolledVars)) - ); - return fn; -}; - -var InterpolateMatrix = { - transformTranslate: true, - transformRotateRadians: true, - transformScale: true, -}; - -var createFunctionString = function(anims) { - // We must track the order they appear in so transforms are applied in the - // correct order. - var orderedMatrixOperations = []; - - // Wrapping function allows the final function to contain state (for - // caching). - var fn = 'return (function() {\n'; - fn += createReusableOperationVars(anims); - fn += 'return function(result, value) {\n'; - fn += ' var didChange = false;\n'; - fn += ' var nextScalarVal;\n'; - fn += ' var ratio;\n'; - - for (var name in anims) { - var anim = anims[name]; - if (anim.type === 'linear') { - if (InterpolateMatrix[name]) { - orderedMatrixOperations.push(name); - var setOperations = [ - computeNextMatrixOperationField(anim, name, X_DIM, 0), - computeNextMatrixOperationField(anim, name, Y_DIM, 1), - computeNextMatrixOperationField(anim, name, Z_DIM, 2) - ]; - if (name === TRANSFORM_ROTATE_NAME) { - setOperations.push(computeNextMatrixOperationField(anim, name, W_DIM, 3)); - } - fn += newlines(setOperations); - } else { - fn += computeNextValLinearScalar(anim, 'nextScalarVal'); - fn += setNextValAndDetectChange(name, 'nextScalarVal'); - } - } else if (anim.type === 'constant') { - fn += computeNextValConstant(anim); - fn += setNextValAndDetectChange(name, 'nextScalarVal'); - } else if (anim.type === 'step') { - fn += computeNextValStep(anim); - fn += setNextValAndDetectChange(name, 'nextScalarVal'); - } else if (anim.type === 'identity') { - fn += computeNextValIdentity(anim); - fn += setNextValAndDetectChange(name, 'nextScalarVal'); - } + var x = computeNextMatrixOperationField(anim, name, X_DIM, 0, value); + var y = computeNextMatrixOperationField(anim, name, Y_DIM, 1, value); + var z = computeNextMatrixOperationField(anim, name, Z_DIM, 2, value); + InterpolateMatrix[name](mat, x, y, z); + if (!didChange) { + didChange = m0 !== mat[0] || m1 !== mat[1] || + m2 !== mat[2] || m3 !== mat[3] || + m4 !== mat[4] || m5 !== mat[5] || + m6 !== mat[6] || m7 !== mat[7] || + m8 !== mat[8] || m9 !== mat[9] || + m10 !== mat[10] || m11 !== mat[11] || + m12 !== mat[12] || m13 !== mat[13] || + m14 !== mat[14] || m15 !== mat[15]; } - if (orderedMatrixOperations.length) { - fn += newlines(setNextMatrixAndDetectChange(orderedMatrixOperations)); - } - fn += ' return didChange;\n'; - fn += '};\n'; - fn += '})()'; - return fn; + return didChange; }; /** @@ -558,15 +148,34 @@ var createFunctionString = function(anims) { * object and returns a boolean describing if any update was actually applied. */ var buildStyleInterpolator = function(anims) { - // Defer compiling this method until we really need it. - var interpolator = null; - function lazyStyleInterpolator(result, value) { - if (interpolator === null) { - interpolator = Function(createFunctionString(anims))(); + function styleInterpolator(result, value) { + var didChange = false; + var didMatrix = false; + for (var name in anims) { + var anim = anims[name]; + if (anim.type === 'linear') { + if (name in InterpolateMatrix) { + didChange = computeTransform(anim, name, value, result, + didChange, didMatrix); + didMatrix = true; + } else { + var next = computeNextValLinearScalar(anim, value); + didChange = setNextValAndDetectChange(result, name, next, didChange); + } + } else if (anim.type === 'constant') { + var next = anim.value; + didChange = setNextValAndDetectChange(result, name, next, didChange); + } else if (anim.type === 'step') { + var next = value >= anim.threshold ? anim.to : anim.from; + didChange = setNextValAndDetectChange(result, name, next, didChange); + } else if (anim.type === 'identity') { + var next = value; + didChange = setNextValAndDetectChange(result, name, next, didChange); + } } - return interpolator(result, value); + return didChange; } - return lazyStyleInterpolator; + return styleInterpolator; }; module.exports = buildStyleInterpolator;