[Web Animations] Expose Web Animations CSS integration as an experimental feature
[WebKit-https.git] / LayoutTests / transitions / resources / transition-test-helpers.js
index e0cef21..ed39e25 100644 (file)
@@ -61,7 +61,7 @@ function compareRGB(rgb, expected, tolerance)
 
 function parseCrossFade(s)
 {
-    var matches = s.match("-webkit-cross-fade\\((.*)\\s*,\\s*(.*)\\s*,\\s*(.*)\\)");
+    var matches = s.match("(?:-webkit-)?cross-fade\\((.*)\\s*,\\s*(.*)\\s*,\\s*(.*)\\)");
 
     if (!matches)
         return null;
@@ -69,17 +69,38 @@ function parseCrossFade(s)
     return {"from": matches[1], "to": matches[2], "percent": parseFloat(matches[3])}
 }
 
+function extractPathValues(path)
+{
+    var components = path.split(' ');
+    var result = [];
+    for (component of components) {
+        var compMatch;
+        if (compMatch = component.match(/[0-9.-]+/)) {
+            result.push(parseFloat(component))
+        }
+    }
+    return result;
+}
+
 function parseClipPath(s)
 {
+    var pathMatch;
+    if (pathMatch = s.match(/path\(((evenodd|nonzero), ?)?\'(.+)\'\)/))
+        return extractPathValues(pathMatch[pathMatch.length - 1]);
+
+    if (pathMatch = s.match(/path\(((evenodd|nonzero), ?)?\"(.+)\"\)/))
+        return extractPathValues(pathMatch[pathMatch.length - 1]);
+
     // FIXME: This only matches a subset of the shape syntax, and the polygon expects 4 points.
     var patterns = [
         /inset\(([\d.]+)\w+ ([\d.]+)\w+\)/,
         /circle\(([\d.]+)\w+ at ([\d.]+)\w+ ([\d.]+)\w+\)/,
         /ellipse\(([\d.]+)\w+ ([\d.]+)\w+ at ([\d.]+)\w+ ([\d.]+)\w+\)/,
-        /polygon\(([\d.]+)\w* ([\d.]+)\w*\, ([\d.]+)\w* ([\d.]+)\w*\, ([\d.]+)\w* ([\d.]+)\w*\, ([\d.]+)\w* ([\d.]+)\w*\)/
+        /polygon\(([\d.]+)\w* ([\d.]+)\w*\, ([\d.]+)\w* ([\d.]+)\w*\, ([\d.]+)\w* ([\d.]+)\w*\, ([\d.]+)\w* ([\d.]+)\w*\)/,
     ];
     
     for (pattern of patterns) {
+        var matchResult;
         if (matchResult = s.match(pattern)) {
             var result = [];
             for (var i = 1; i < matchResult.length; ++i)
@@ -92,6 +113,77 @@ function parseClipPath(s)
     return null;
 }
 
+function hasFloatValue(value)
+{
+    switch (value.primitiveType) {
+    case CSSPrimitiveValue.CSS_FR:
+    case CSSPrimitiveValue.CSS_NUMBER:
+    case CSSPrimitiveValue.CSS_PARSER_INTEGER:
+    case CSSPrimitiveValue.CSS_PERCENTAGE:
+    case CSSPrimitiveValue.CSS_EMS:
+    case CSSPrimitiveValue.CSS_EXS:
+    case CSSPrimitiveValue.CSS_CHS:
+    case CSSPrimitiveValue.CSS_REMS:
+    case CSSPrimitiveValue.CSS_PX:
+    case CSSPrimitiveValue.CSS_CM:
+    case CSSPrimitiveValue.CSS_MM:
+    case CSSPrimitiveValue.CSS_IN:
+    case CSSPrimitiveValue.CSS_PT:
+    case CSSPrimitiveValue.CSS_PC:
+    case CSSPrimitiveValue.CSS_DEG:
+    case CSSPrimitiveValue.CSS_RAD:
+    case CSSPrimitiveValue.CSS_GRAD:
+    case CSSPrimitiveValue.CSS_TURN:
+    case CSSPrimitiveValue.CSS_MS:
+    case CSSPrimitiveValue.CSS_S:
+    case CSSPrimitiveValue.CSS_HZ:
+    case CSSPrimitiveValue.CSS_KHZ:
+    case CSSPrimitiveValue.CSS_DIMENSION:
+    case CSSPrimitiveValue.CSS_VW:
+    case CSSPrimitiveValue.CSS_VH:
+    case CSSPrimitiveValue.CSS_VMIN:
+    case CSSPrimitiveValue.CSS_VMAX:
+    case CSSPrimitiveValue.CSS_DPPX:
+    case CSSPrimitiveValue.CSS_DPI:
+    case CSSPrimitiveValue.CSS_DPCM:
+        return true;
+    }
+    return false;
+}
+
+function getNumericValue(cssValue)
+{
+    if (hasFloatValue(cssValue.primitiveType))
+        return cssValue.getFloatValue(cssValue.primitiveType);
+
+    return -1;
+}
+
+function isCalcPrimitiveValue(value)
+{
+    switch (value.primitiveType) {
+    case 113: // CSSPrimitiveValue.CSS_CALC:
+    case 114: // CSSPrimitiveValue.CSS_CALC_PERCENTAGE_WITH_NUMBER:
+    case 115: // CSSPrimitiveValue.CSS_CALC_PERCENTAGE_WITH_LENGTH:
+    return true;
+    }
+    return false;
+}
+
+function extractNumbersFromCalcExpression(value, values)
+{
+    var calcRegexp = /^calc\((.+)\)$/;
+    var result = calcRegexp.exec(value.cssText);
+    var numberMatch = /([^\.\-0-9]*)(-?[\.0-9]+)/;
+    var remainder = result[1];
+    var match;
+    while ((match = numberMatch.exec(remainder)) !== null) {
+        var skipLength = match[1].length + match[2].length;
+        values.push(parseFloat(match[2]))
+        remainder = remainder.substr(skipLength + 1);
+    }
+}
+
 function checkExpectedValue(expected, index)
 {
     var time = expected[index][0];
@@ -176,23 +268,27 @@ function checkExpectedValue(expected, index)
         if (computedStyle.cssValueType == CSSValue.CSS_VALUE_LIST) {
             var values = [];
             for (var i = 0; i < computedStyle.length; ++i) {
-                switch (computedStyle[i].cssValueType) {
+                var styleValue = computedStyle[i];
+                switch (styleValue.cssValueType) {
                   case CSSValue.CSS_PRIMITIVE_VALUE:
-                    values.push(computedStyle[i].getFloatValue(CSSPrimitiveValue.CSS_NUMBER));
+                    if (hasFloatValue(styleValue))
+                        values.push(styleValue.getFloatValue(CSSPrimitiveValue.CSS_NUMBER));
+                    else if (isCalcPrimitiveValue(styleValue))
+                        extractNumbersFromCalcExpression(styleValue, values);
                     break;
                   case CSSValue.CSS_CUSTOM:
                     // arbitrarily pick shadow-x and shadow-y
                     if (isShadow) {
-                      var shadowXY = getShadowXY(computedStyle[i]);
+                      var shadowXY = getShadowXY(styleValue);
                       values.push(shadowXY[0]);
                       values.push(shadowXY[1]);
                     } else
-                      values.push(computedStyle[i].cssText);
+                      values.push(styleValue.cssText);
                     break;
                 }
             }
             computedValue = values.join(',');
-            pass = true;
+            pass = values.length > 0;
             for (var i = 0; i < values.length; ++i)
                 pass &= isCloseEnough(values[i], expectedValue[i], tolerance);
         } else if (computedStyle.cssValueType == CSSValue.CSS_PRIMITIVE_VALUE) {
@@ -254,6 +350,31 @@ function checkExpectedValueCallback(expected, index)
     return function() { checkExpectedValue(expected, index); };
 }
 
+const prefix = "-webkit-";
+const propertiesRequiringPrefix = ["-webkit-text-stroke-color", "-webkit-text-fill-color"];
+
+function pauseTransitionAtTimeOnElement(transitionProperty, time, element)
+{
+    // If we haven't opted into CSS Animations and CSS Transitions as Web Animations, use the internal API.
+    if ('internals' in window && !internals.settings.webAnimationsCSSIntegrationEnabled())
+        return internals.pauseTransitionAtTimeOnElement(transitionProperty, time, element);
+
+    if (transitionProperty.startsWith(prefix) && !propertiesRequiringPrefix.includes(transitionProperty))
+        transitionProperty = transitionProperty.substr(prefix.length);
+
+    // Otherwise, use the Web Animations API.
+    const animations = element.getAnimations();
+    for (let animation of animations) {
+        if (animation instanceof CSSTransition && animation.transitionProperty == transitionProperty) {
+            animation.currentTime = time * 1000;
+            animation.pause();
+            return true;
+        }
+    }
+    console.log(`A transition for property ${transitionProperty} could not be found`);
+    return false;
+}
+
 function runTest(expected, usePauseAPI)
 {
     var maxTime = 0;
@@ -271,7 +392,7 @@ function runTest(expected, usePauseAPI)
         if (hasPauseTransitionAPI && usePauseAPI) {
             if (tryToPauseTransition) {
               var element = document.getElementById(elementId);
-              if (!internals.pauseTransitionAtTimeOnElement(property, time, element))
+              if (!pauseTransitionAtTimeOnElement(property, time, element))
                 window.console.log("Failed to pause '" + property + "' transition on element '" + elementId + "'");
             }
             checkExpectedValue(expected, i);
@@ -312,12 +433,10 @@ function startTest(expected, usePauseAPI, callback)
 }
 
 var result = "";
-var hasPauseTransitionAPI;
+var hasPauseTransitionAPI = true;
 
 function runTransitionTest(expected, callback, usePauseAPI, doPixelTest)
 {
-    hasPauseTransitionAPI = 'internals' in window;
-    
     if (window.testRunner) {
         if (!doPixelTest)
             testRunner.dumpAsText();