mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-10-08 12:21:44 -04:00
Merge pull request #3621 from lightpanda-io/legacy-constructors
webapi: Legacy constuctor API
This commit is contained in:
4 files changed
+105
-15
No files matched your search
+45
-15
@@ -326,22 +326,18 @@ fn createSnapshotContext(
|
||||
const template_index = comptime bridge.JsApiLookup.getId(JsApi);
|
||||
const func = v8.v8__FunctionTemplate__GetFunction(templates[template_index], context);
|
||||
if (@hasDecl(JsApi.Meta, "name")) {
|
||||
const name = JsApi.Meta.name;
|
||||
const v8_class_name = v8.v8__String__NewFromUtf8(isolate, name.ptr, v8.kNormal, @intCast(name.len));
|
||||
var maybe_result: v8.MaybeBool = undefined;
|
||||
// Web IDL: interface objects on the global are non-enumerable.
|
||||
v8.v8__Object__DefineOwnProperty(global_obj, context, v8_class_name, func, v8.DontEnum, &maybe_result);
|
||||
|
||||
if (@hasDecl(JsApi.Meta, "constructor_alias")) {
|
||||
const alias = JsApi.Meta.constructor_alias;
|
||||
const v8_class_name = v8.v8__String__NewFromUtf8(isolate, alias.ptr, v8.kNormal, @intCast(alias.len));
|
||||
var maybe_result: v8.MaybeBool = undefined;
|
||||
v8.v8__Object__Set(global_obj, context, v8_class_name, func, &maybe_result);
|
||||
|
||||
const name = JsApi.Meta.name;
|
||||
const illegal_class_name = v8.v8__String__NewFromUtf8(isolate, name.ptr, v8.kNormal, @intCast(name.len));
|
||||
var maybe_result2: v8.MaybeBool = undefined;
|
||||
v8.v8__Object__DefineOwnProperty(global_obj, context, illegal_class_name, func, 0, &maybe_result2);
|
||||
} else {
|
||||
const name = JsApi.Meta.name;
|
||||
const v8_class_name = v8.v8__String__NewFromUtf8(isolate, name.ptr, v8.kNormal, @intCast(name.len));
|
||||
var maybe_result: v8.MaybeBool = undefined;
|
||||
// Web IDL: interface objects on the global are non-enumerable.
|
||||
v8.v8__Object__DefineOwnProperty(global_obj, context, v8_class_name, func, v8.DontEnum, &maybe_result);
|
||||
const alias_func = generateLegacyFactoryFunction(JsApi, isolate, templates[template_index], func.?, context.?);
|
||||
const v8_alias_name = v8.v8__String__NewFromUtf8(isolate, alias.ptr, v8.kNormal, @intCast(alias.len));
|
||||
var maybe_alias_result: v8.MaybeBool = undefined;
|
||||
v8.v8__Object__DefineOwnProperty(global_obj, context, v8_alias_name, @ptrCast(alias_func), v8.DontEnum, &maybe_alias_result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -721,7 +717,9 @@ fn protoIndexLookup(comptime JsApi: type) ?u16 {
|
||||
// Generate a constructor template for a JsApi type (public for reuse)
|
||||
fn generateConstructor(comptime JsApi: type, isolate: *v8.Isolate) *const v8.FunctionTemplate {
|
||||
const callback, const arity = comptime blk: {
|
||||
if (@hasDecl(JsApi, "constructor")) {
|
||||
// The constructor belongs to the legacy factory function (`Image`),
|
||||
// see generateLegacyFactoryFunction.
|
||||
if (@hasDecl(JsApi, "constructor") and !@hasDecl(JsApi.Meta, "constructor_alias")) {
|
||||
break :blk .{ JsApi.constructor.func, JsApi.constructor.arity };
|
||||
}
|
||||
if (inheritsFromHtmlElement(JsApi)) {
|
||||
@@ -749,6 +747,38 @@ fn generateConstructor(comptime JsApi: type, isolate: *v8.Isolate) *const v8.Fun
|
||||
return template;
|
||||
}
|
||||
|
||||
// https://webidl.spec.whatwg.org/#legacy-factory-functions
|
||||
// `Image`, `Audio`, `Option`: a function distinct from the interface object
|
||||
// (so `new HTMLImageElement()` stays illegal and `Image.name` is "Image"),
|
||||
// whose `prototype` is the interface's prototype object.
|
||||
fn generateLegacyFactoryFunction(comptime JsApi: type, isolate: *v8.Isolate, interface_template: *const v8.FunctionTemplate, interface_func: *const v8.Function, context: *const v8.Context) *const v8.Function {
|
||||
const alias = JsApi.Meta.constructor_alias;
|
||||
const template = v8.v8__FunctionTemplate__New__Config(isolate, &.{
|
||||
.length = JsApi.constructor.arity,
|
||||
.callback = JsApi.constructor.func,
|
||||
.behavior = v8.kConstructorBehavior_Allow,
|
||||
}).?;
|
||||
// Inherit so that the objects we construct pass the interface's
|
||||
// accessor and method signature checks.
|
||||
v8.v8__FunctionTemplate__Inherit(template, interface_template);
|
||||
{
|
||||
const internal_field_count = comptime countInternalFields(JsApi);
|
||||
if (internal_field_count > 0) {
|
||||
const instance_template = v8.v8__FunctionTemplate__InstanceTemplate(template);
|
||||
v8.v8__ObjectTemplate__SetInternalFieldCount(instance_template, internal_field_count);
|
||||
}
|
||||
}
|
||||
const class_name = v8.v8__String__NewFromUtf8(isolate, alias.ptr, v8.kNormal, @intCast(alias.len));
|
||||
v8.v8__FunctionTemplate__SetClassName(template, class_name);
|
||||
|
||||
const func = v8.v8__FunctionTemplate__GetFunction(template, context).?;
|
||||
const prototype_key = v8.v8__String__NewFromUtf8(isolate, "prototype", v8.kNormal, 9);
|
||||
const interface_prototype = v8.v8__Object__Get(@ptrCast(interface_func), context, prototype_key).?;
|
||||
var maybe_result: v8.MaybeBool = undefined;
|
||||
v8.v8__Object__DefineOwnProperty(@ptrCast(func), context, prototype_key, interface_prototype, v8.ReadOnly + v8.DontEnum + v8.DontDelete, &maybe_result);
|
||||
return func;
|
||||
}
|
||||
|
||||
// hard-coded special case for HtmlElement which can be extended but not
|
||||
// instantiated.
|
||||
fn inheritsFromHtmlElement(comptime JsApi: type) bool {
|
||||
|
||||
@@ -179,3 +179,23 @@
|
||||
img.src = 'data:image/gif;base64,R0lGODlhAQABAAAAACw=';
|
||||
testing.expectEqual(undefined, await img.decode());
|
||||
</script>
|
||||
|
||||
<script id="legacy_factory_function">
|
||||
// https://webidl.spec.whatwg.org/#legacy-factory-functions
|
||||
testing.expectEqual(true, Image !== HTMLImageElement)
|
||||
testing.expectEqual('Image', Image.name)
|
||||
testing.expectEqual(0, Image.length)
|
||||
testing.expectEqual(HTMLImageElement.prototype, Image.prototype)
|
||||
testing.expectEqual(HTMLImageElement, new Image().constructor)
|
||||
testing.expectEqual('img', new Image().localName)
|
||||
testing.expectError('TypeError', () => new HTMLImageElement())
|
||||
testing.expectError('TypeError', () => Image())
|
||||
|
||||
const desc = Object.getOwnPropertyDescriptor(Image, 'prototype')
|
||||
testing.expectEqual(false, desc.writable)
|
||||
testing.expectEqual(false, desc.enumerable)
|
||||
testing.expectEqual(false, desc.configurable)
|
||||
|
||||
testing.expectEqual(false, Object.keys(window).includes('Image'))
|
||||
testing.expectEqual(false, Object.keys(window).includes('HTMLImageElement'))
|
||||
</script>
|
||||
@@ -308,3 +308,23 @@
|
||||
testing.expectEqual(true, video.paused);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="legacy_factory_function">
|
||||
// https://webidl.spec.whatwg.org/#legacy-factory-functions
|
||||
testing.expectEqual(true, Audio !== HTMLAudioElement)
|
||||
testing.expectEqual('Audio', Audio.name)
|
||||
testing.expectEqual(0, Audio.length)
|
||||
testing.expectEqual(HTMLAudioElement.prototype, Audio.prototype)
|
||||
testing.expectEqual(HTMLAudioElement, new Audio().constructor)
|
||||
testing.expectEqual('audio', new Audio().localName)
|
||||
testing.expectError('TypeError', () => new HTMLAudioElement())
|
||||
testing.expectError('TypeError', () => Audio())
|
||||
|
||||
const desc = Object.getOwnPropertyDescriptor(Audio, 'prototype')
|
||||
testing.expectEqual(false, desc.writable)
|
||||
testing.expectEqual(false, desc.enumerable)
|
||||
testing.expectEqual(false, desc.configurable)
|
||||
|
||||
testing.expectEqual(false, Object.keys(window).includes('Audio'))
|
||||
testing.expectEqual(false, Object.keys(window).includes('HTMLAudioElement'))
|
||||
</script>
|
||||
@@ -257,3 +257,23 @@
|
||||
testing.expectEqual(1, select.selectedIndex)
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="legacy_factory_function">
|
||||
// https://webidl.spec.whatwg.org/#legacy-factory-functions
|
||||
testing.expectEqual(true, Option !== HTMLOptionElement)
|
||||
testing.expectEqual('Option', Option.name)
|
||||
testing.expectEqual(0, Option.length)
|
||||
testing.expectEqual(HTMLOptionElement.prototype, Option.prototype)
|
||||
testing.expectEqual(HTMLOptionElement, new Option().constructor)
|
||||
testing.expectEqual('option', new Option().localName)
|
||||
testing.expectError('TypeError', () => new HTMLOptionElement())
|
||||
testing.expectError('TypeError', () => Option())
|
||||
|
||||
const desc = Object.getOwnPropertyDescriptor(Option, 'prototype')
|
||||
testing.expectEqual(false, desc.writable)
|
||||
testing.expectEqual(false, desc.enumerable)
|
||||
testing.expectEqual(false, desc.configurable)
|
||||
|
||||
testing.expectEqual(false, Object.keys(window).includes('Option'))
|
||||
testing.expectEqual(false, Object.keys(window).includes('HTMLOptionElement'))
|
||||
</script>
|
||||
Reference in new issue
Block a user