Skip to content
This repository was archived by the owner on Feb 26, 2024. It is now read-only.

Commit 7ca3995

Browse files
JiaLiPassionmhevery
authored andcommitted
feat(patch): fix #696, patch HTMLCanvasElement.toBlob as MacroTask (#788)
1 parent 67634ae commit 7ca3995

File tree

3 files changed

+95
-11
lines changed

3 files changed

+95
-11
lines changed

Diff for: lib/browser/browser.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88

99
import {patchTimer} from '../common/timers';
10-
import {findEventTask, patchClass, patchEventTargetMethods, patchMethod, patchOnProperties, patchPrototype, zoneSymbol} from '../common/utils';
10+
import {findEventTask, patchClass, patchEventTargetMethods, patchMacroTask, patchMethod, patchOnProperties, patchPrototype, zoneSymbol} from '../common/utils';
1111

1212
import {propertyPatch} from './define-property';
1313
import {eventTargetPatch} from './event-target';
@@ -55,6 +55,16 @@ Zone.__load_patch('on_property', (global: any, Zone: ZoneType, api: _ZonePrivate
5555
registerElementPatch(global);
5656
});
5757

58+
Zone.__load_patch('canvas', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
59+
const HTMLCanvasElement = global['HTMLCanvasElement'];
60+
if (typeof HTMLCanvasElement !== 'undefined' && HTMLCanvasElement.prototype &&
61+
HTMLCanvasElement.prototype.toBlob) {
62+
patchMacroTask(HTMLCanvasElement.prototype, 'toBlob', (self: any, args: any[]) => {
63+
return {name: 'HTMLCanvasElement.toBlob', target: self, callbackIndex: 0, args: args};
64+
});
65+
}
66+
});
67+
5868
Zone.__load_patch('XHR', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
5969
// Treat XMLHTTPRequest as a macrotask.
6070
patchXHR(global);

Diff for: test/browser/browser.spec.ts

+52-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88

99
import {isBrowser, isMix, zoneSymbol} from '../../lib/common/utils';
10-
import {ifEnvSupports} from '../test-util';
10+
import {ifEnvSupports, ifEnvSupportsWithDone} from '../test-util';
1111

1212
import Spy = jasmine.Spy;
1313
declare const global: any;
@@ -54,6 +54,17 @@ function supportEventListenerOptions() {
5454

5555
(supportEventListenerOptions as any).message = 'supportsEventListenerOptions';
5656

57+
function supportCanvasTest() {
58+
const HTMLCanvasElement = (window as any)['HTMLCanvasElement'];
59+
const supportCanvas = typeof HTMLCanvasElement !== 'undefined' && HTMLCanvasElement.prototype &&
60+
HTMLCanvasElement.prototype.toBlob;
61+
const FileReader = (window as any)['FileReader'];
62+
const supportFileReader = typeof FileReader !== 'undefined';
63+
return supportCanvas && supportFileReader;
64+
}
65+
66+
(supportCanvasTest as any).message = 'supportCanvasTest';
67+
5768
describe('Zone', function() {
5869
const rootZone = Zone.current;
5970
(Zone as any)[zoneSymbol('ignoreConsoleErrorUncaughtError')] = true;
@@ -666,5 +677,45 @@ describe('Zone', function() {
666677
});
667678
}));
668679
});
680+
681+
it('HTMLCanvasElement.toBlob should be a ZoneAware MacroTask',
682+
ifEnvSupportsWithDone(supportCanvasTest, (done: Function) => {
683+
const canvas = document.createElement('canvas');
684+
const d = canvas.width;
685+
const ctx = canvas.getContext('2d');
686+
ctx.beginPath();
687+
ctx.moveTo(d / 2, 0);
688+
ctx.lineTo(d, d);
689+
ctx.lineTo(0, d);
690+
ctx.closePath();
691+
ctx.fillStyle = 'yellow';
692+
ctx.fill();
693+
694+
const scheduleSpy = jasmine.createSpy('scheduleSpy');
695+
const zone: Zone = Zone.current.fork({
696+
name: 'canvas',
697+
onScheduleTask:
698+
(delegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, task: Task) => {
699+
scheduleSpy();
700+
return delegate.scheduleTask(targetZone, task);
701+
}
702+
});
703+
704+
zone.run(() => {
705+
const canvasData = canvas.toDataURL();
706+
canvas.toBlob(function(blob) {
707+
expect(Zone.current.name).toEqual('canvas');
708+
expect(scheduleSpy).toHaveBeenCalled();
709+
710+
const reader = new FileReader();
711+
reader.readAsDataURL(blob);
712+
reader.onloadend = function() {
713+
const base64data = reader.result;
714+
expect(base64data).toEqual(canvasData);
715+
done();
716+
};
717+
});
718+
});
719+
}));
669720
});
670721
});

Diff for: test/test-util.ts

+32-9
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,38 @@
2222
* ifEnvSupports(supportsOnClick, function() { ... });
2323
*/
2424
declare const global: any;
25-
export function ifEnvSupports(test: any, block: Function) {
26-
return function() {
27-
const message = (test.message || test.name || test);
28-
if (typeof test === 'string' ? !!global[test] : test()) {
29-
block();
25+
export function ifEnvSupports(test: any, block: Function): () => void {
26+
return _ifEnvSupports(test, block);
27+
}
28+
29+
export function ifEnvSupportsWithDone(test: any, block: Function): (done: Function) => void {
30+
return _ifEnvSupports(test, block, true);
31+
}
32+
33+
function _ifEnvSupports(test: any, block: Function, withDone = false) {
34+
if (withDone) {
35+
return function(done?: Function) {
36+
_runTest(test, block, done);
37+
};
38+
} else {
39+
return function() {
40+
_runTest(test, block, undefined);
41+
};
42+
}
43+
}
44+
45+
function _runTest(test: any, block: Function, done: Function) {
46+
const message = (test.message || test.name || test);
47+
if (typeof test === 'string' ? !!global[test] : test()) {
48+
if (done) {
49+
block(done);
3050
} else {
31-
it('should skip the test if the API does not exist', function() {
32-
console.log('WARNING: skipping ' + message + ' tests (missing this API)');
33-
});
51+
block();
3452
}
35-
};
53+
} else {
54+
done && done();
55+
it('should skip the test if the API does not exist', function() {
56+
console.log('WARNING: skipping ' + message + ' tests (missing this API)');
57+
});
58+
}
3659
}

0 commit comments

Comments
 (0)