| // 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:expect/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(); | |
| }); | |
| } |