Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Canvas API #380

Merged
merged 118 commits into from
May 9, 2019
Merged

Conversation

delima02
Copy link
Contributor

@delima02 delima02 commented Mar 21, 2019

  • Implementation of the Canvas API in the worker thread.
  • This will work for Chrome and FireFox (the latter if the user explicitly enables OffscreenCanvas).
  • 04/16/2019: OffscreenCanvas Polyfill has been added to this PR. Most CanvasRenderingContext2D methods will now work on all browsers.

@choumx @jridgewell

@kristoferbaxter kristoferbaxter self-requested a review March 22, 2019 04:37
@kristoferbaxter
Copy link
Contributor

Going to request this change holds off until the buffer branch lands since it will change the messaging format.

I'll review the changes tomorrow.

src/test/htmlcanvaselement/context.ts Outdated Show resolved Hide resolved
src/test/htmlcanvaselement/context.ts Outdated Show resolved Hide resolved
src/test/htmlcanvaselement/context.ts Outdated Show resolved Hide resolved
src/test/htmlcanvaselement/context.ts Outdated Show resolved Hide resolved
src/test/htmlcanvaselement/context.ts Outdated Show resolved Hide resolved
src/test/htmlcanvaselement/context.ts Outdated Show resolved Hide resolved
src/test/tsconfig.json Outdated Show resolved Hide resolved
src/test/tsconfig.json Outdated Show resolved Hide resolved
src/test/tsconfig.json Outdated Show resolved Hide resolved
src/test/htmlcanvaselement/context.ts Outdated Show resolved Hide resolved
@delima02 delima02 changed the title Implement Canvas API for browsers that support OffscreenCanvas [WIP] Implement Canvas API for browsers that support OffscreenCanvas Mar 29, 2019
@delima02 delima02 changed the title [WIP] Implement Canvas API for browsers that support OffscreenCanvas Implement Canvas API for browsers that support OffscreenCanvas Mar 30, 2019
@delima02
Copy link
Contributor Author

@jridgewell ready for review 👍

Copy link
Collaborator

@dreamofabear dreamofabear left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a test page I can try this code out on? I'm not quite sure I follow the control flow.

package.json Outdated Show resolved Hide resolved
src/worker-thread/dom/HTMLCanvasElement.ts Outdated Show resolved Hide resolved
src/worker-thread/CanvasRenderingContext2D.ts Outdated Show resolved Hide resolved
src/worker-thread/CanvasRenderingContext2D.ts Outdated Show resolved Hide resolved
src/worker-thread/CanvasRenderingContext2D.ts Outdated Show resolved Hide resolved
@delima02 delima02 changed the title Implement Canvas API for browsers that support OffscreenCanvas [wip] Implement Canvas API for browsers that support OffscreenCanvas Apr 1, 2019
if (DEBUG_ENABLED) {
console.info('debug', 'messageToWorker', readableMessageToWorker(this.nodeContext, message));
}
if (this.config.onSendMessage) {
this.config.onSendMessage(message);
}
this.worker.postMessage(message);
this.worker.postMessage(message, transferables);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be an optional parameter instead of forcing all messages without transferables to pass an empty array?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes :)

src/test/htmlcanvaselement/context.test.ts Outdated Show resolved Hide resolved
});

describe('clearRect', () => {
test('context calls clearRect', t => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using a fake describe() is mixing testing paradigms. Better to just use comment blocks and stick to Ava style.

Discussion thread if you're curious: avajs/ava#222

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks!

});
});

describe('rota
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/spy/setter

A "spy" isn't the right name to describe this function.

});
});

describe('rota
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:)

src/worker-thread/CanvasRenderingContext2D.ts Outdated Show resolved Hide resolved
@@ -20,6 +20,10 @@ declare interface Sanitizer {
mutateProperty(node: Node, prop: string, value: string): boolean;
}

declare interface HTMLCanvasElement {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a comment explaining why we need to declare this here. I assume it's because OffscreenCanvas types is not available in TS yet?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct.transferControlToOffscreen is not detected as a method because of this.

}
};

// TODO: This should only happen in test environemnet. Otherwise, we should throw.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix and remove TODOs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will include this in a later PR (there is not a simple way to do this currently, and it does not affect the operation of this API outside of testing environment)

this.delegate('restore', [...arguments], false);
}

// canvas property is readonly. We don't want to implement getters, but this must be here
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't want to implement getters

What does this mean?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nvm, getters are included now.

src/worker-thread/DOMTypes.ts Outdated Show resolved Hide resolved

export function OffscreenPolyfillCallProcessor(strings: Strings, workerContext: WorkerContext): CommandExecutor {
return {
execute(mutations: Uint16Array, startPosition: number, target: RenderableElement): number {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have tests that cover these processor functions?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now we do 👍

src/test/htmlcanvaselement/context.test.ts Outdated Show resolved Hide resolved
src/test/htmlcanvaselement/context.test.ts Outdated Show resolved Hide resolved
return this.implementation;
}
}
(global as any).OffscreenCanvas = OffscreenCanvas;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ruh roh. Globals are generally bad, especially this global since it includes the test runner.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this new approach seem like a good idea?

constructor() {
// this.x, y
const context = ({} as unknown) as CanvasRenderingContext2D;
OffscreenCanvas.mostRecentInstance = this;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this look weird to you? :)

Also, do we need it? Why can't this be referenced via canvas.getContext('2d').implementation?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From our discussion yesterday: this is actually needed for calls that happen before the upgraded (auto-synchronized) version of OffscreenCanvas is fetched from the main-thread.

src/test/htmlcanvaselement/context.test.ts Show resolved Hide resolved
src/test/htmlcanvaselement/context.test.ts Outdated Show resolved Hide resolved
src/worker-thread/canvas/CanvasRenderingContext2D.ts Outdated Show resolved Hide resolved
src/worker-thread/canvas/CanvasRenderingContext2D.ts Outdated Show resolved Hide resolved
src/worker-thread/canvas/CanvasRenderingContext2D.ts Outdated Show resolved Hide resolved
src/worker-thread/canvas/CanvasRenderingContext2D.ts Outdated Show resolved Hide resolved
Copy link
Collaborator

@dreamofabear dreamofabear left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure that any code review comments are applied across all instances in your PR e.g. using globals. Comments can be addressed after merge.

src/test/htmlcanvaselement/context.test.ts Show resolved Hide resolved
constructor() {
// this.x, y
const context = ({} as unknown) as CanvasRenderingContext2D;
FakeOffscreenCanvas.mostRecentInstance = this;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still an issue. Remember what we discussed was the possible solution for this?

src/test/DocumentCreation.ts Show resolved Hide resolved
src/test/DocumentCreation.ts Show resolved Hide resolved
function createSetterStub(obj: any, property: string, spy: () => {}) {
obj[property] = 'existent';
sandbox.stub(obj, property).set(spy);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

import { CanvasRenderingContext2D } from '../../worker-thread/canvas/CanvasTypes';
import { createTestingDocument } from '../DocumentCreation';

const test = anyTest as TestInterface<{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is 3K lines of code. We should first remove redundant tests (no need to test same upgrade code path more than once) and then split it up if necessary (how should we segment it?).

const { context2d, deferredUpgrade, implementation, sandbox } = t.context;
const instance = new FakeOffscreenCanvas();

const instanceStub = (instance.getContext('2d')['clearRect'] = sandbox.stub());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand how this local FakeOffscreenCanvas instance is at all related to the <canvas> element created in beforeEach.

src/test/main-thread/offscreen-canvas.test.ts Show resolved Hide resolved
@dreamofabear dreamofabear merged commit 443f62e into ampproject:master May 9, 2019
@dreamofabear dreamofabear mentioned this pull request Jul 23, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants