// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. library canvas_rendering_context_2d_test; import 'dart:async'; import 'dart:html'; import 'dart:math'; import 'canvas_rendering_util.dart'; import 'package:async_helper/async_helper.dart'; // These videos and base64 strings are the same video, representing 2 // frames of 8x8 red pixels. // The videos were created with: // convert -size 8x8 xc:red blank1.jpg // convert -size 8x8 xc:red blank2.jpg // avconv -f image2 -i "blank%d.jpg" -c:v libx264 small.mp4 // avconv -i small.mp4 small.webm // python -m base64 -e small.mp4 // python -m base64 -e small.webm var mp4VideoUrl = '/root_dart/tests/lib/html/small.mp4'; var webmVideoUrl = '/root_dart/tests/lib/html/small.webm'; var mp4VideoDataUrl = 'data:video/mp4;base64,AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAA' 'AIZnJlZQAAAsdtZGF0AAACmwYF//+X3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlID' 'EyMCByMjE1MSBhM2Y0NDA3IC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZW' 'Z0IDIwMDMtMjAxMSAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG' '9wdGlvbnM6IGNhYmFjPTEgcmVmPTMgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MToweD' 'ExMSBtZT1oZXggc3VibWU9NyBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj' '0wIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MSA4eDhkY3Q9MCBjcW09MC' 'BkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0tMiB0aH' 'JlYWRzPTE4IHNsaWNlZF90aHJlYWRzPTAgbnI9MCBkZWNpbWF0ZT0xIGludGVybGFjZW' 'Q9MCBibHVyYXlfY29tcGF0PTAgY29uc3RyYWluZWRfaW50cmE9MCBiZnJhbWVzPTMgYl' '9weXJhbWlkPTAgYl9hZGFwdD0xIGJfYmlhcz0wIGRpcmVjdD0xIHdlaWdodGI9MCBvcG' 'VuX2dvcD0xIHdlaWdodHA9MiBrZXlpbnQ9MjUwIGtleWludF9taW49MjUgc2NlbmVjdX' 'Q9NDAgaW50cmFfcmVmcmVzaD0wIHJjX2xvb2thaGVhZD00MCByYz1jcmYgbWJ0cmVlPT' 'EgY3JmPTUxLjAgcWNvbXA9MC42MCBxcG1pbj0wIHFwbWF4PTY5IHFwc3RlcD00IGlwX3' 'JhdGlvPTEuMjUgYXE9MToxLjAwAIAAAAARZYiEB//3aoK5/tP9+8yeuIEAAAAHQZoi2P' '/wgAAAAzxtb292AAAAbG12aGQAAAAAAAAAAAAAAAAAAAPoAAAAUAABAAABAAAAAAAAAA' 'AAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAA' 'AAAAAAAAAAAAAAAAAAAAACAAAAGGlvZHMAAAAAEICAgAcAT/////7/AAACUHRyYWsAAA' 'BcdGtoZAAAAA8AAAAAAAAAAAAAAAEAAAAAAAAAUAAAAAAAAAAAAAAAAAAAAAAAAQAAAA' 'AAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAACAAAAAgAAAAAACRlZHRzAAAAHG' 'Vsc3QAAAAAAAAAAQAAAFAAAAABAAEAAAAAAchtZGlhAAAAIG1kaGQAAAAAAAAAAAAAAA' 'AAAAAZAAAAAlXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSG' 'FuZGxlcgAAAAFzbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZg' 'AAAAAAAAABAAAADHVybCAAAAABAAABM3N0YmwAAACXc3RzZAAAAAAAAAABAAAAh2F2Yz' 'EAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAACAAIAEgAAABIAAAAAAAAAAEAAAAAAAAAAA' 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAxYXZjQwFNQAr/4QAYZ01ACuiPyy' '4C2QAAAwABAAADADIPEiUSAQAGaOvAZSyAAAAAGHN0dHMAAAAAAAAAAQAAAAIAAAABAA' 'AAFHN0c3MAAAAAAAAAAQAAAAEAAAAYY3R0cwAAAAAAAAABAAAAAgAAAAEAAAAcc3RzYw' 'AAAAAAAAABAAAAAQAAAAEAAAABAAAAHHN0c3oAAAAAAAAAAAAAAAIAAAK0AAAACwAAAB' 'hzdGNvAAAAAAAAAAIAAAAwAAAC5AAAAGB1ZHRhAAAAWG1ldGEAAAAAAAAAIWhkbHIAAA' 'AAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAK2lsc3QAAAAjqXRvbwAAABtkYXRhAAAAAQ' 'AAAABMYXZmNTMuMjEuMQ=='; var webmVideoDataUrl = 'data:video/webm;base64,GkXfowEAAAAAAAAfQoaBAUL3gQFC8oEEQvOBCEKChHdlY' 'm1Ch4ECQoWBAhhTgGcBAAAAAAAB/hFNm3RALE27i1OrhBVJqWZTrIHfTbuMU6uEFlSua' '1OsggEsTbuMU6uEHFO7a1OsggHk7AEAAAAAAACkAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVSalmAQAAAAAAA' 'EEq17GDD0JATYCLTGF2ZjUzLjIxLjFXQYtMYXZmNTMuMjEuMXOkkJatuHwTJ7cvFLSzB' 'Smxbp5EiYhAVAAAAAAAABZUrmsBAAAAAAAAR64BAAAAAAAAPteBAXPFgQGcgQAitZyDd' 'W5khoVWX1ZQOIOBASPjg4QCYloA4AEAAAAAAAASsIEIuoEIVLCBCFS6gQhUsoEDH0O2d' 'QEAAAAAAABZ54EAo72BAACA8AIAnQEqCAAIAABHCIWFiIWEiAICAnWqA/gD+gINTRgA/' 'v0hRf/kb+PnRv/I4//8WE8DijI//FRAo5WBACgAsQEAARAQABgAGFgv9AAIAAAcU7trA' 'QAAAAAAAA67jLOBALeH94EB8YIBfw=='; Future testWithThreeParams() async { setupFunc(); video.onError.listen((_) { throw ('URL failed to load.'); }); if (video.canPlayType('video/webm; codecs="vp8.0, vorbis"', '') != '') { video.src = webmVideoUrl; } else if (video.canPlayType( 'video/mp4; codecs="avc1.4D401E, mp4a.40.2"', null) != '') { video.src = mp4VideoUrl; } else { window.console.log('Video is not supported on this system.'); } // Without user interaction, playing the video requires autoplay to be enabled // and autoplay can only be enabled if muted. We loop the video so there is // always an active frame that can be drawn. video.loop = true; video.muted = true; video.autoplay = true; await video.play(); context.drawImage(video, 50, 50); expectPixelFilled(50, 50); expectPixelFilled(54, 54); expectPixelFilled(57, 57); expectPixelUnfilled(58, 58); expectPixelUnfilled(0, 0); expectPixelUnfilled(70, 70); tearDownFunc(); } Future testWithFiveParams() async { setupFunc(); video.onError.listen((_) { throw ('URL failed to load.'); }); if (video.canPlayType('video/webm; codecs="vp8.0, vorbis"', '') != '') { video.src = webmVideoUrl; } else if (video.canPlayType( 'video/mp4; codecs="avc1.4D401E, mp4a.40.2"', null) != '') { video.src = mp4VideoUrl; } else { // TODO(amouravski): Better fallback? window.console.log('Video is not supported on this system.'); } video.loop = true; video.muted = true; video.autoplay = true; await video.play(); context.drawImageToRect(video, new Rectangle(50, 50, 20, 20)); expectPixelFilled(50, 50); expectPixelFilled(55, 55); expectPixelFilled(59, 59); expectPixelFilled(60, 60); expectPixelFilled(69, 69); expectPixelUnfilled(70, 70); expectPixelUnfilled(0, 0); expectPixelUnfilled(80, 80); tearDownFunc(); } Future testWithNineParams() async { setupFunc(); video.onError.listen((_) { throw ('URL failed to load.'); }); if (video.canPlayType('video/webm; codecs="vp8.0, vorbis"', '') != '') { video.src = webmVideoUrl; } else if (video.canPlayType( 'video/mp4; codecs="avc1.4D401E, mp4a.40.2"', null) != '') { video.src = mp4VideoUrl; } else { // TODO(amouravski): Better fallback? window.console.log('Video is not supported on this system.'); } video.loop = true; video.muted = true; video.autoplay = true; await video.play(); context.drawImageToRect(video, new Rectangle(50, 50, 20, 20), sourceRect: new Rectangle(2, 2, 6, 6)); expectPixelFilled(50, 50); expectPixelFilled(55, 55); expectPixelFilled(59, 59); expectPixelFilled(60, 60); expectPixelFilled(69, 69); expectPixelUnfilled(70, 70); expectPixelUnfilled(0, 0); expectPixelUnfilled(80, 80); tearDownFunc(); } Future testDataUrlWithNineParams() async { setupFunc(); video = new VideoElement(); canvas = new CanvasElement(); video.onError.listen((_) { throw ('URL failed to load.'); }); if (video.canPlayType('video/webm; codecs="vp8.0, vorbis"', '') != '') { video.src = webmVideoDataUrl; } else if (video.canPlayType( 'video/mp4; codecs="avc1.4D401E, mp4a.40.2"', null) != '') { video.src = mp4VideoDataUrl; } else { // TODO(amouravski): Better fallback? window.console.log('Video is not supported on this system.'); } video.loop = true; video.muted = true; video.autoplay = true; await video.play(); context.drawImageToRect(video, new Rectangle(50, 50, 20, 20), sourceRect: new Rectangle(2, 2, 6, 6)); expectPixelFilled(50, 50); expectPixelFilled(55, 55); expectPixelFilled(59, 59); expectPixelFilled(60, 60); expectPixelFilled(69, 69); expectPixelUnfilled(70, 70); expectPixelUnfilled(0, 0); expectPixelUnfilled(80, 80); tearDownFunc(); } main() { asyncTest(() async { await testWithThreeParams(); await testWithFiveParams(); await testWithNineParams(); await testDataUrlWithNineParams(); }); }