| Index: LayoutTests/media/video-autoplay-experiment-modes.html | 
| diff --git a/LayoutTests/media/video-autoplay-experiment-modes.html b/LayoutTests/media/video-autoplay-experiment-modes.html | 
| index 41042561431443708c69e06abc316dfc2b988e5a..7b8fcb269f85b60e36bc8c55270a3560dfa4bd07 100644 | 
| --- a/LayoutTests/media/video-autoplay-experiment-modes.html | 
| +++ b/LayoutTests/media/video-autoplay-experiment-modes.html | 
| @@ -12,9 +12,10 @@ | 
| Flags  - autoplay experiment setting being tested. | 
| a      - "foraudio" | 
| v      - "forvideo" | 
| +               V      - "ifviewport" | 
| M      - "ifmuted" | 
| p      - "playmuted" | 
| -               For example, EM means "enabled-ifmuted". | 
| +               For example, vM means '-forvideo-ifmuted". | 
| This test does not check -ifmobile since that check always | 
| fails outside of android. | 
| Type   - audio or video element? | 
| @@ -28,8 +29,15 @@ | 
| none - media is not muted. | 
| attr - muted attribute is set on the element. | 
| js   - muted property is set after media is ready to play. | 
| +  View   - is media in viewport? | 
| +               onscreen  - element starts out onscreen. | 
| +               scroll    - element starts offscreen, scrolled into view once | 
| +                           it is ready to play. | 
| +               offscreen - element starts out offscreen and stays offscreen. | 
|  | 
| == Test Outputs == | 
| +  Early?  - did playback start before element was scrolled onscreen?  For | 
| +            tests in which View!=scroll, this is reported as "-". | 
| Played? - did playback start by the conclusion of the test? | 
| Muted?  - was the media muted?  If the media didn't play, then this is | 
| reported as "-". | 
| @@ -42,6 +50,8 @@ | 
| <td>Type</td> | 
| <td>Play w/</td> | 
| <td>Mute</td> | 
| +<td>View</td> | 
| +<td>Early?</td> | 
| <td>Played?</td> | 
| <td>Muted?</td> | 
| </tr> | 
| @@ -55,13 +65,19 @@ var configNumber = 0; | 
|  | 
| var mediaFile = findMediaFile("video", "content/test"); | 
| var onscreenParent = document.createElement("div"); | 
| +// The onscreen parent's height is also used to make sure that the off-screen | 
| +// parent is, in fact, off-screen. | 
| +onscreenParent.style.height="1000px"; | 
| document.body.insertBefore(onscreenParent, document.body.firstChild); | 
| +// Also create another root that's off the bottom of the window. | 
| +var offscreenParent = document.createElement("div"); | 
| +document.body.appendChild(offscreenParent); | 
|  | 
| -function didPlaybackStart(video) | 
| +function didPlaybackStart(element) | 
| { | 
| -    // We say that the video started if it's not paused or if it played and | 
| +    // We say that the element started if it's not paused or if it played and | 
| // already ended. | 
| -    return !video.paused || video.ended; | 
| +    return !element.paused || element.ended; | 
| } | 
|  | 
| function addResultsRow(spec) | 
| @@ -78,18 +94,19 @@ function addResultsRow(spec) | 
| var smallType = ""; | 
| smallType += (type.indexOf("-forvideo")>-1)?"v":""; | 
| smallType += (type.indexOf("-foraudio")>-1)?"a":""; | 
| +    smallType += (type.indexOf("-ifviewport")>-1)?"V":""; | 
| smallType += (type.indexOf("-ifmuted")>-1)?"M":""; | 
| smallType += (type.indexOf("-playmuted")>-1)?"p":""; | 
| row.insertCell(-1).innerText = smallType; | 
|  | 
| // Add remaining fields. | 
| -    var fields = [ "elementType", "autoplayType", "mutedType", "played", | 
| -        "muted"]; | 
| +    var fields = [ "elementType", "autoplayType", "mutedType", "visType", | 
| +        "playedEarly", "played", "muted"]; | 
| for(idx in fields) | 
| row.insertCell(-1).innerText = spec[fields[idx]].substring(0,7); | 
| } | 
|  | 
| -function configureVideoViaScript(element, spec) | 
| +function configureElementViaScript(element, spec) | 
| { | 
| if (spec.mutedType == "js") | 
| element.muted = true; | 
| @@ -113,6 +130,9 @@ function checkElementStatus(element) | 
| addResultsRow(element.spec); | 
| element.parentElement.removeChild(element); | 
|  | 
| +    // Scroll back to the top, in case this was a scrolling test. | 
| +    onscreenParent.scrollIntoView(); | 
| + | 
| queueNextExperiment(); | 
| } | 
|  | 
| @@ -122,8 +142,13 @@ function runOneConfig(spec) | 
|  | 
| // Create, configure, and attach a media element. | 
| var element = document.createElement(spec.elementType); | 
| +    element.setAttribute("controls", "true"); | 
|  | 
| -    onscreenParent.appendChild(element); | 
| +    // Pick whether the element will be visible when canPlayThrough. | 
| +    if (spec.visType == "onscreen") | 
| +        onscreenParent.appendChild(element); | 
| +    else | 
| +        offscreenParent.appendChild(element); | 
|  | 
| // Set any attributes before canPlayThrough. | 
| if (spec.mutedType == "attr") | 
| @@ -131,6 +156,8 @@ function runOneConfig(spec) | 
| if (spec.autoplayType == "attr") | 
| element.setAttribute("autoplay", "true"); | 
|  | 
| +    spec.playedEarly = "-"; | 
| + | 
| // Record the spec in the element, so that we can display the | 
| // results later. | 
| element.spec = spec; | 
| @@ -140,10 +167,28 @@ function runOneConfig(spec) | 
| element.addEventListener("canplaythrough", function() | 
| { | 
| // Now that we can play, if we're supposed to play / mute via js do so. | 
| -        configureVideoViaScript(element, spec); | 
| - | 
| -        // Record the results. | 
| -        checkElementStatus(element); | 
| +        configureElementViaScript(element, spec); | 
| + | 
| +        // If we're supposed to scroll the item onscreen after it is ready to | 
| +        // play, then do so now. | 
| +        if(spec.visType == "scroll") { | 
| +            // Record the play state here, too, before we scroll. | 
| +            spec.playedEarly = didPlaybackStart(element) ? "yes" : "no"; | 
| + | 
| +            // We are supposed to scroll the player into view. | 
| +            element.scrollIntoView(true); | 
| +            // We cause two visibility checks.  The first notices the scroll, | 
| +            // while the second notices that scrolling has stopped. | 
| +            // It would be nicer to trigger location polling here, but that | 
| +            // can take ~second to notice that scrolling is stopped. | 
| +            window.internals.triggerAutoplayViewportCheck(element); | 
| +            window.internals.triggerAutoplayViewportCheck(element); | 
| +            // Once those are return, the state should be correct. | 
| +            checkElementStatus(element, spec); | 
| +        } else { | 
| +            // Record the results immediately. | 
| +            checkElementStatus(element, spec); | 
| +        } | 
| }); | 
|  | 
| // Set the source, which will eventually lead to canPlayThrough. | 
| @@ -153,13 +198,16 @@ function runOneConfig(spec) | 
| var experimentTypes = [ | 
| "none", | 
| "enabled-forvideo", | 
| -    "enabled-forvideo-ifmuted", | 
| -    "enabled-forvideo-playmuted", | 
| +    "enabled-forvideo-ifviewport", | 
| +    "enabled-forvideo-ifviewport-ifmuted", | 
| +    "enabled-forvideo-ifviewport-playmuted", | 
| "enabled-foraudio", | 
| +    "enabled-foraudio-ifviewport", | 
| ]; | 
| var elementTypes = ["video", "audio"]; | 
| var autoplayTypes = ["none", "attr", "play()"]; | 
| var mutedTypes = ["none", "attr", "js"]; | 
| +var visTypes = ["onscreen", "scroll", "offscreen"]; | 
|  | 
| function runNextConfig() | 
| { | 
| @@ -176,6 +224,8 @@ function runNextConfig() | 
| exp = Math.floor(exp / autoplayTypes.length); | 
| spec.mutedType = mutedTypes[exp % mutedTypes.length]; | 
| exp = Math.floor(exp / mutedTypes.length); | 
| +    spec.visType = visTypes[exp % visTypes.length]; | 
| +    exp = Math.floor(exp / visTypes.length); | 
| spec.experimentNumber = configNumber; | 
|  | 
| // exp>0 here indicates that we've wrapped around. | 
| @@ -187,7 +237,26 @@ function runNextConfig() | 
|  | 
| // To keep the test fast, skip a few combinations. | 
| var skip = false; | 
| -    if (spec.experimentType.indexOf("-ifmuted") == -1 && spec.mutedType != "none") | 
| +    var mismatched =(spec.elementType == "video" | 
| +        && spec.experimentType.indexOf("-foraudio") > -1) | 
| +        || (spec.elementType == "audio" | 
| +        && spec.experimentType.indexOf("-forvideo") > -1); | 
| + | 
| +    if (spec.autoplayType == "none" && spec.visType != 'onscreen') | 
| +        skip = true; | 
| +    else if (spec.experimentType.indexOf("-ifmuted") > -1 && spec.visType != "onscreen") | 
| +        skip = true; | 
| +    else if (spec.visType == "offscreen" && spec.autoplayType != "attr") | 
| +        skip = true; | 
| +    else if (spec.experimentType.indexOf("-ifmuted") == -1 && spec.mutedType != "none") | 
| +        skip = true; | 
| +    else if (spec.elementType == "audio" && spec.mutedType != "none") | 
| +        skip = true; | 
| +    else if (spec.elementType == "audio" && spec.visType != "scroll") | 
| +        skip = true; | 
| +    else if (mismatched && spec.visType !="onscreen") | 
| +        skip = true; | 
| +    else if (mismatched && spec.autoplayType != "attr") | 
| skip = true; | 
|  | 
| if (skip) | 
|  |