Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / LayoutTests / animations / resources / animation-test-helpers.js
1 /* This is the helper function to run animation tests:
2
3 Test page requirements:
4 - The body must contain an empty div with id "result"
5 - Call this function directly from the <script> inside the test page
6
7 Function parameters:
8     expected [required]: an array of arrays defining a set of CSS properties that must have given values at specific times (see below)
9     callbacks [optional]: a function to be executed immediately after animation starts;
10                           or, an object in the form {time: function} containing functions to be
11                           called at the specified times (in seconds) during animation.
12     trigger [optional]: a function to trigger transitions at the start of the test
13
14     Each sub-array must contain these items in this order:
15     - the time in seconds at which to snapshot the CSS property
16     - the id of the element on which to get the CSS property value [1]
17     - the name of the CSS property to get [2]
18     - the expected value for the CSS property
19     - the tolerance to use when comparing the effective CSS property value with its expected value
20
21     [1] If a single string is passed, it is the id of the element to test. If an array with 2 elements is passed they
22     are the ids of 2 elements, whose values are compared for equality. In this case the expected value is ignored
23     but the tolerance is used in the comparison. If the second element is prefixed with "static:", no animation on that
24     element is required, allowing comparison with an unanimated "expected value" element.
25
26     If a string with a '.' is passed, this is an element in an iframe. The string before the dot is the iframe id
27     and the string after the dot is the element name in that iframe.
28
29     [2] If the CSS property name is "webkitTransform", expected value must be an array of 1 or more numbers corresponding to the matrix elements,
30     or a string which will be compared directly (useful if the expected value is "none")
31     If the CSS property name is "webkitTransform.N", expected value must be a number corresponding to the Nth element of the matrix
32
33 */
34
35 // Set to true to log debug information in failing tests. Note that these logs
36 // contain timestamps, so are non-deterministic and will introduce flakiness if
37 // any expected results include failures.
38 var ENABLE_ERROR_LOGGING = false;
39
40 function isCloseEnough(actual, desired, tolerance)
41 {
42     if (typeof desired === "string")
43         return actual === desired;
44     var diff = Math.abs(actual - desired);
45     return diff <= tolerance;
46 }
47
48 function roundNumber(num, decimalPlaces)
49 {
50   return Math.round(num * Math.pow(10, decimalPlaces)) / Math.pow(10, decimalPlaces);
51 }
52
53 function matrixStringToArray(s)
54 {
55     if (s == "none")
56         return [ 1, 0, 0, 1, 0, 0 ];
57     var m = s.split("(");
58     m = m[1].split(")");
59     return m[0].split(",");
60 }
61
62 function parseCrossFade(s)
63 {
64     var matches = s.match("-webkit-cross-fade\\((.*)\\s*,\\s*(.*)\\s*,\\s*(.*)\\)");
65
66     if (!matches)
67         return null;
68
69     return {"from": matches[1], "to": matches[2], "percent": parseFloat(matches[3])}
70 }
71
72 function parseBasicShape(s)
73 {
74     var functionParse = s.match(/(\w+)\((.+)\)/);
75     if (!functionParse)
76         return null;
77
78     var name = functionParse[1];
79     var params = functionParse[2];
80     params = params.split(/\s*[,\s]\s*/);
81
82     // Parse numbers and normalize percentages
83     for (var i = 0; i < params.length; ++i) {
84         var param = params[i];
85         if (!/$\d/.test(param))
86             continue;
87         params[i] = parseFloat(params[i]);
88         if (param.indexOf('%') != -1)
89             params[i] = params[i] / 100;
90     }
91
92     return {"shape": name, "params": params};
93 }
94
95 function basicShapeParametersMatch(paramList1, paramList2, tolerance)
96 {
97     if (paramList1.shape != paramList2.shape
98         || paramList1.params.length != paramList2.params.length)
99         return false;
100     for (var i = 0; i < paramList1.params.length; ++i) {
101         var param1 = paramList1.params[i], 
102             param2 = paramList2.params[i];
103         var match = isCloseEnough(param1, param2, tolerance);
104         if (!match)
105             return false;
106     }
107     return true;
108 }
109
110 // Return an array of numeric filter params in 0-1.
111 function getFilterParameters(s)
112 {
113     var filterResult = s.match(/(\w+)\((.+)\)/);
114     if (!filterResult)
115         throw new Error("There's no filter in \"" + s + "\"");
116     var filterParams = filterResult[2];
117     var paramList = filterParams.split(' '); // FIXME: the spec may allow comma separation at some point.
118     
119     // Normalize percentage values.
120     for (var i = 0; i < paramList.length; ++i) {
121         var param = paramList[i];
122         paramList[i] = parseFloat(paramList[i]);
123         if (param.indexOf('%') != -1)
124             paramList[i] = paramList[i] / 100;
125     }
126
127     return paramList;
128 }
129
130 function filterParametersMatch(paramList1, paramList2, tolerance)
131 {
132     if (paramList1.length != paramList2.length)
133         return false;
134     for (var i = 0; i < paramList1.length; ++i) {
135         var param1 = paramList1[i], 
136             param2 = paramList2[i];
137         var match = isCloseEnough(param1, param2, tolerance);
138         if (!match)
139             return false;
140     }
141     return true;
142 }
143
144 function checkExpectedValue(expected, index)
145 {
146     log('Checking expectation: ' + JSON.stringify(expected[index]));
147     var time = expected[index][0];
148     var elementId = expected[index][1];
149     var property = expected[index][2];
150     var expectedValue = expected[index][3];
151     var tolerance = expected[index][4];
152
153     // Check for a pair of element Ids
154     var compareElements = false;
155     var element2Static = false;
156     var elementId2;
157     if (typeof elementId != "string") {
158         if (elementId.length != 2)
159             return;
160             
161         elementId2 = elementId[1];
162         elementId = elementId[0];
163
164         if (elementId2.indexOf("static:") == 0) {
165             elementId2 = elementId2.replace("static:", "");
166             element2Static = true;
167         }
168
169         compareElements = true;
170     }
171
172     // Check for a dot separated string
173     var iframeId;
174     if (!compareElements) {
175         var array = elementId.split('.');
176         if (array.length == 2) {
177             iframeId = array[0];
178             elementId = array[1];
179         }
180     }
181
182     var computedValue, computedValue2;
183     if (compareElements) {
184         computedValue = getPropertyValue(property, elementId, iframeId);
185         computedValue2 = getPropertyValue(property, elementId2, iframeId);
186
187         if (comparePropertyValue(property, computedValue, computedValue2, tolerance))
188             result += "PASS - \"" + property + "\" property for \"" + elementId + "\" and \"" + elementId2 + 
189                             "\" elements at " + time + "s are close enough to each other" + "<br>";
190         else
191             result += "FAIL - \"" + property + "\" property for \"" + elementId + "\" and \"" + elementId2 + 
192                             "\" elements at " + time + "s saw: \"" + computedValue + "\" and \"" + computedValue2 + 
193                                             "\" which are not close enough to each other" + "<br>";
194     } else {
195         var elementName;
196         if (iframeId)
197             elementName = iframeId + '.' + elementId;
198         else
199             elementName = elementId;
200
201         computedValue = getPropertyValue(property, elementId, iframeId);
202
203         if (comparePropertyValue(property, computedValue, expectedValue, tolerance))
204             result += "PASS - \"" + property + "\" property for \"" + elementName + "\" element at " + time + 
205                             "s saw something close to: " + expectedValue + "<br>";
206         else
207             result += "FAIL - \"" + property + "\" property for \"" + elementName + "\" element at " + time + 
208                             "s expected: " + expectedValue + " but saw: " + computedValue + "<br>";
209     }
210 }
211
212 function compareRGB(rgb, expected, tolerance)
213 {
214     return (isCloseEnough(parseInt(rgb[0]), expected[0], tolerance) &&
215             isCloseEnough(parseInt(rgb[1]), expected[1], tolerance) &&
216             isCloseEnough(parseInt(rgb[2]), expected[2], tolerance));
217 }
218
219 function checkExpectedTransitionValue(expected, index)
220 {
221     log('Checking expectation: ' + JSON.stringify(expected[index]));
222     var time = expected[index][0];
223     var elementId = expected[index][1];
224     var property = expected[index][2];
225     var expectedValue = expected[index][3];
226     var tolerance = expected[index][4];
227     var postCompletionCallback = expected[index][5];
228
229     var computedValue;
230     var pass = false;
231     var transformRegExp = /^-webkit-transform(\.\d+)?$/;
232     if (transformRegExp.test(property)) {
233         computedValue = window.getComputedStyle(document.getElementById(elementId)).webkitTransform;
234         if (typeof expectedValue === "string" || computedValue === "none")
235             pass = (computedValue == expectedValue);
236         else if (typeof expectedValue === "number") {
237             var m = computedValue.split("(");
238             var m = m[1].split(",");
239             pass = isCloseEnough(parseFloat(m[parseInt(property.substring(18))]), expectedValue, tolerance);
240         } else {
241             var m = computedValue.split("(");
242             var m = m[1].split(",");
243             for (i = 0; i < expectedValue.length; ++i) {
244                 pass = isCloseEnough(parseFloat(m[i]), expectedValue[i], tolerance);
245                 if (!pass)
246                     break;
247             }
248         }
249     } else if (property == "fill" || property == "stroke" || property == "stop-color" || property == "flood-color" || property == "lighting-color") {
250         computedValue = window.getComputedStyle(document.getElementById(elementId)).getPropertyCSSValue(property);
251         // The computedValue cssText is rgb(num, num, num)
252         var components = computedValue.cssText.split("(")[1].split(")")[0].split(",");
253         if (compareRGB(components, expectedValue, tolerance))
254             pass = true;
255         else {
256             // We failed. Make sure computed value is something we can read in the error message
257             computedValue = computedValue.cssText;
258         }
259     } else if (property == "lineHeight") {
260         computedValue = parseInt(window.getComputedStyle(document.getElementById(elementId)).lineHeight);
261         pass = isCloseEnough(computedValue, expectedValue, tolerance);
262     } else if (property == "background-image"
263                || property == "border-image-source"
264                || property == "border-image"
265                || property == "list-style-image"
266                || property == "-webkit-mask-image"
267                || property == "-webkit-mask-box-image") {
268         if (property == "border-image" || property == "-webkit-mask-image" || property == "-webkit-mask-box-image")
269             property += "-source";
270
271         computedValue = window.getComputedStyle(document.getElementById(elementId)).getPropertyCSSValue(property).cssText;
272         computedCrossFade = parseCrossFade(computedValue);
273
274         if (!computedCrossFade) {
275             pass = false;
276         } else {
277             pass = isCloseEnough(computedCrossFade.percent, expectedValue, tolerance);
278         }
279     } else if (property == "object-position") {
280         computedValue = window.getComputedStyle(document.getElementById(elementId)).objectPosition;
281         var actualArray = computedValue.split(" ");
282         var expectedArray = expectedValue.split(" ");
283         if (actualArray.length != expectedArray.length) {
284             pass = false;
285         } else {
286             for (i = 0; i < expectedArray.length; ++i) {
287                 pass = isCloseEnough(parseFloat(actualArray[i]), parseFloat(expectedArray[i]), tolerance);
288                 if (!pass)
289                     break;
290             }
291         }
292     } else if (property === "shape-inside" || property === "shape-outside") {
293         computedValue = window.getComputedStyle(document.getElementById(elementId)).getPropertyValue(property);
294         var actualShape = parseBasicShape(computedValue);
295         var expectedShape = parseBasicShape(expectedValue);
296         pass = basicShapeParametersMatch(actualShape, expectedShape, tolerance);
297     } else {
298         var computedStyle = window.getComputedStyle(document.getElementById(elementId)).getPropertyCSSValue(property);
299         if (computedStyle.cssValueType == CSSValue.CSS_VALUE_LIST) {
300             var values = [];
301             for (var i = 0; i < computedStyle.length; ++i) {
302                 switch (computedStyle[i].cssValueType) {
303                   case CSSValue.CSS_PRIMITIVE_VALUE:
304                     if (computedStyle[i].primitiveType == CSSPrimitiveValue.CSS_STRING)
305                         values.push(computedStyle[i].getStringValue());
306                     else
307                         values.push(computedStyle[i].getFloatValue(CSSPrimitiveValue.CSS_NUMBER));
308                     break;
309                   case CSSValue.CSS_CUSTOM:
310                     // arbitrarily pick shadow-x and shadow-y
311                     if (property == 'box-shadow' || property == 'text-shadow') {
312                       var text = computedStyle[i].cssText;
313                       // Shadow cssText looks like "rgb(0, 0, 255) 0px -3px 10px 0px" and can be fractional.
314                       var shadowPositionRegExp = /\)\s*(-?[\d.]+)px\s*(-?[\d.]+)px/;
315                       var match = shadowPositionRegExp.exec(text);
316                       var shadowXY = [parseInt(match[1]), parseInt(match[2])];
317                       values.push(shadowXY[0]);
318                       values.push(shadowXY[1]);
319                     } else
320                       values.push(computedStyle[i].cssText);
321                     break;
322                 }
323             }
324             computedValue = values.join(',');
325             pass = true;
326             for (var i = 0; i < values.length; ++i)
327                 pass &= isCloseEnough(values[i], expectedValue[i], tolerance);
328         } else if (computedStyle.cssValueType == CSSValue.CSS_PRIMITIVE_VALUE) {
329             switch (computedStyle.primitiveType) {
330                 case CSSPrimitiveValue.CSS_STRING:
331                 case CSSPrimitiveValue.CSS_IDENT:
332                     computedValue = computedStyle.getStringValue();
333                     pass = computedValue == expectedValue;
334                     break;
335                 case CSSPrimitiveValue.CSS_RGBCOLOR:
336                     var rgbColor = computedStyle.getRGBColorValue();
337                     computedValue = [rgbColor.red.getFloatValue(CSSPrimitiveValue.CSS_NUMBER),
338                                      rgbColor.green.getFloatValue(CSSPrimitiveValue.CSS_NUMBER),
339                                      rgbColor.blue.getFloatValue(CSSPrimitiveValue.CSS_NUMBER)]; // alpha is not exposed to JS
340                     pass = true;
341                     for (var i = 0; i < 3; ++i)
342                         pass &= isCloseEnough(computedValue[i], expectedValue[i], tolerance);
343                     break;
344                 case CSSPrimitiveValue.CSS_RECT:
345                     computedValue = computedStyle.getRectValue();
346                     computedValue = [computedValue.top.getFloatValue(CSSPrimitiveValue.CSS_NUMBER),
347                                      computedValue.right.getFloatValue(CSSPrimitiveValue.CSS_NUMBER),
348                                      computedValue.bottom.getFloatValue(CSSPrimitiveValue.CSS_NUMBER),
349                                      computedValue.left.getFloatValue(CSSPrimitiveValue.CSS_NUMBER)];
350                      pass = true;
351                      for (var i = 0; i < 4; ++i)
352                          pass &= isCloseEnough(computedValue[i], expectedValue[i], tolerance);
353                     break;
354                 case CSSPrimitiveValue.CSS_PERCENTAGE:
355                     computedValue = parseFloat(computedStyle.cssText);
356                     pass = isCloseEnough(computedValue, expectedValue, tolerance);
357                     break;
358                 default:
359                     computedValue = computedStyle.getFloatValue(CSSPrimitiveValue.CSS_NUMBER);
360                     pass = isCloseEnough(computedValue, expectedValue, tolerance);
361             }
362         }
363     }
364
365     if (pass)
366         result += "PASS - \"" + property + "\" property for \"" + elementId + "\" element at " + time + "s saw something close to: " + expectedValue + "<br>";
367     else
368         result += "FAIL - \"" + property + "\" property for \"" + elementId + "\" element at " + time + "s expected: " + expectedValue + " but saw: " + computedValue + "<br>";
369
370     if (postCompletionCallback)
371       result += postCompletionCallback();
372 }
373
374
375 function getPropertyValue(property, elementId, iframeId)
376 {
377     var computedValue;
378     var element;
379     if (iframeId)
380         element = document.getElementById(iframeId).contentDocument.getElementById(elementId);
381     else
382         element = document.getElementById(elementId);
383
384     if (property == "lineHeight")
385         computedValue = parseInt(window.getComputedStyle(element).lineHeight);
386     else if (property == "backgroundImage"
387                || property == "borderImageSource"
388                || property == "listStyleImage"
389                || property == "webkitMaskImage"
390                || property == "webkitMaskBoxImage"
391                || property == "webkitFilter"
392                || property == "webkitClipPath"
393                || property == "shapeInside"
394                || !property.indexOf("webkitTransform")) {
395         computedValue = window.getComputedStyle(element)[property.split(".")[0]];
396     } else {
397         var computedStyle = window.getComputedStyle(element).getPropertyCSSValue(property);
398         try {
399             computedValue = computedStyle.getFloatValue(CSSPrimitiveValue.CSS_NUMBER);
400         } catch (e) {
401             computedValue = computedStyle.cssText;
402         }
403     }
404
405     return computedValue;
406 }
407
408 function comparePropertyValue(property, computedValue, expectedValue, tolerance)
409 {
410     var result = true;
411
412     if (!property.indexOf("webkitTransform")) {
413         if (typeof expectedValue == "string")
414             result = (computedValue == expectedValue);
415         else if (typeof expectedValue == "number") {
416             var m = matrixStringToArray(computedValue);
417             result = isCloseEnough(parseFloat(m[parseInt(property.substring(16))]), expectedValue, tolerance);
418         } else {
419             var m = matrixStringToArray(computedValue);
420             for (i = 0; i < expectedValue.length; ++i) {
421                 result = isCloseEnough(parseFloat(m[i]), expectedValue[i], tolerance);
422                 if (!result)
423                     break;
424             }
425         }
426     } else if (property == "webkitFilter") {
427         var filterParameters = getFilterParameters(computedValue);
428         var filter2Parameters = getFilterParameters(expectedValue);
429         result = filterParametersMatch(filterParameters, filter2Parameters, tolerance);
430     } else if (property == "webkitClipPath" || property == "shapeInside") {
431         var clipPathParameters = parseBasicShape(computedValue);
432         var clipPathParameters2 = parseBasicShape(expectedValue);
433         if (!clipPathParameters || !clipPathParameters2)
434             result = false;
435         result = basicShapeParametersMatch(clipPathParameters, clipPathParameters2, tolerance);
436     } else if (property == "backgroundImage"
437                || property == "borderImageSource"
438                || property == "listStyleImage"
439                || property == "webkitMaskImage"
440                || property == "webkitMaskBoxImage") {
441         var computedCrossFade = parseCrossFade(computedValue);
442
443         if (!computedCrossFade) {
444             result = false;
445         } else {
446             if (typeof expectedValue == "string") {
447                 var computedCrossFade2 = parseCrossFade(expectedValue);
448                 result = isCloseEnough(computedCrossFade.percent, computedCrossFade2.percent, tolerance) && computedCrossFade.from == computedCrossFade2.from && computedCrossFade.to == computedCrossFade2.to;
449             } else {
450                 result = isCloseEnough(computedCrossFade.percent, expectedValue, tolerance)
451             }
452         }
453     } else {
454         if (typeof expectedValue == "string")
455             result = (computedValue == expectedValue);
456         else
457             result = isCloseEnough(computedValue, expectedValue, tolerance);
458     }
459     return result;
460 }
461
462 function endTest()
463 {
464     log('Ending test');
465     var resultElement = useResultElement ? document.getElementById('result') : document.documentElement;
466     if (ENABLE_ERROR_LOGGING && result.indexOf('FAIL') >= 0)
467         result += '<br>Log:<br>' + logMessages.join('<br>');
468     resultElement.innerHTML = result;
469
470     if (window.testRunner)
471         testRunner.notifyDone();
472 }
473
474 function runChecksWithRAF(checks)
475 {
476     var finished = true;
477     var time = performance.now() - animStartTime;
478
479     log('RAF callback, animation time: ' + time);
480     for (var k in checks) {
481         var checkTime = Number(k);
482         if (checkTime > time) {
483             finished = false;
484             break;
485         }
486         log('Running checks for time: ' + checkTime + ', delay: ' + (time - checkTime));
487         checks[k].forEach(function(check) { check(); });
488         delete checks[k];
489     }
490
491     if (finished)
492         endTest();
493     else
494         requestAnimationFrame(runChecksWithRAF.bind(null, checks));
495 }
496
497 function runChecksWithPauseAPI(checks) {
498     for (var k in checks) {
499         var timeMs = Number(k);
500         log('Pausing at time: ' + timeMs + ', active animations: ' + internals.numberOfActiveAnimations());
501         internals.pauseAnimations(timeMs / 1000);
502         checks[k].forEach(function(check) { check(); });
503     }
504     endTest();
505 }
506
507 function startTest(checks)
508 {
509     if (hasPauseAnimationAPI)
510         runChecksWithPauseAPI(checks);
511     else {
512         result += 'Warning this test is running in real-time and may be flaky.<br>';
513         runChecksWithRAF(checks);
514     }
515 }
516
517 var logMessages = [];
518 var useResultElement = false;
519 var result = "";
520 var hasPauseAnimationAPI;
521 var animStartTime;
522 var isTransitionsTest = false;
523
524 function log(message)
525 {
526     logMessages.push(performance.now() + ' - ' + message);
527 }
528
529 function waitForAnimationsToStart(callback)
530 {
531     if (!window.internals || internals.numberOfActiveAnimations() > 0) {
532         callback();
533     } else {
534         setTimeout(waitForAnimationsToStart.bind(this, callback), 0);
535     }
536 }
537
538 // FIXME: disablePauseAnimationAPI and doPixelTest
539 function runAnimationTest(expected, callbacks, trigger, disablePauseAnimationAPI, doPixelTest, startTestImmediately)
540 {
541     log('runAnimationTest');
542     if (!expected)
543         throw "Expected results are missing!";
544
545     hasPauseAnimationAPI = 'internals' in window;
546     if (disablePauseAnimationAPI)
547         hasPauseAnimationAPI = false;
548
549     var checks = {};
550
551     if (typeof callbacks == 'function') {
552         checks[0] = [callbacks];
553     } else for (var time in callbacks) {
554         timeMs = Math.round(time * 1000);
555         checks[timeMs] = [callbacks[time]];
556     }
557
558     for (var i = 0; i < expected.length; i++) {
559         var expectation = expected[i];
560         var timeMs = Math.round(expectation[0] * 1000);
561         if (!checks[timeMs])
562             checks[timeMs] = [];
563         if (isTransitionsTest)
564             checks[timeMs].push(checkExpectedTransitionValue.bind(null, expected, i));
565         else
566             checks[timeMs].push(checkExpectedValue.bind(null, expected, i));
567     }
568
569     var doPixelTest = Boolean(doPixelTest);
570     useResultElement = doPixelTest;
571
572     if (window.testRunner) {
573         if (doPixelTest) {
574             testRunner.dumpAsTextWithPixelResults();
575         } else {
576             testRunner.dumpAsText();
577         }
578         testRunner.waitUntilDone();
579     }
580
581     var started = false;
582
583     function begin() {
584         if (!started) {
585             log('First ' + event + ' event fired');
586             started = true;
587             if (trigger) {
588                 trigger();
589                 document.documentElement.offsetTop
590             }
591             waitForAnimationsToStart(function() {
592                 log('Finished waiting for animations to start');
593                 animStartTime = performance.now();
594                 startTest(checks);
595             });
596         }
597     }
598
599     var startTestImmediately = Boolean(startTestImmediately);
600     if (startTestImmediately) {
601         begin();
602     } else {
603         var target = isTransitionsTest ? window : document;
604         var event = isTransitionsTest ? 'load' : 'webkitAnimationStart';
605         target.addEventListener(event, begin, false);
606     }
607 }
608
609 /* This is the helper function to run transition tests:
610
611 Test page requirements:
612 - The body must contain an empty div with id "result"
613 - Call this function directly from the <script> inside the test page
614
615 Function parameters:
616     expected [required]: an array of arrays defining a set of CSS properties that must have given values at specific times (see below)
617     trigger [optional]: a function to be executed just before the test starts (none by default)
618     callbacks [optional]: an object in the form {timeS: function} specifing callbacks to be made during the test
619     doPixelTest [optional]: whether to dump pixels during the test (false by default)
620     disablePauseAnimationAPI [optional]: whether to disable the pause API and run a RAF-based test (false by default)
621
622     Each sub-array must contain these items in this order:
623     - the time in seconds at which to snapshot the CSS property
624     - the id of the element on which to get the CSS property value
625     - the name of the CSS property to get [1]
626     - the expected value for the CSS property
627     - the tolerance to use when comparing the effective CSS property value with its expected value
628
629     [1] If the CSS property name is "-webkit-transform", expected value must be an array of 1 or more numbers corresponding to the matrix elements,
630     or a string which will be compared directly (useful if the expected value is "none")
631     If the CSS property name is "-webkit-transform.N", expected value must be a number corresponding to the Nth element of the matrix
632
633 */
634 function runTransitionTest(expected, trigger, callbacks, doPixelTest, disablePauseAnimationAPI) {
635     isTransitionsTest = true;
636     runAnimationTest(expected, callbacks, trigger, disablePauseAnimationAPI, doPixelTest);
637 }