Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion moli-renderer-v8/src/context_bootstrap/canvas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ const WEBGL_SUPPORTED_EXTENSIONS: &[&str] = &[
];

#[derive(WebApiFunctionTemplate)]
#[webapi(name = "HTMLCanvasElement")]
#[webapi(name = "HTMLCanvasElement", receiver = crate::native_bridge::receivers::html_canvas_element)]
struct HtmlCanvasElementPrototypeAccessorsDeclaration {
#[webapi(
accessor_property,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ pub(in crate::context_bootstrap) use events::{
};
pub(super) use font_face::{
font_face_constructor_callback, font_face_load_callback, install_font_face_template_accessors,
is_font_face,
};
pub(super) use font_face_set::{
font_face_set_add_callback, font_face_set_add_event_listener_callback,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ struct FontFaceObjectDeclaration<'s> {
}

#[derive(WebApiFunctionTemplate)]
#[webapi(name = "FontFace")]
#[webapi(name = "FontFace", receiver = is_font_face)]
struct FontFacePrototypeAccessorsDeclaration {
#[webapi(
accessor_property,
Expand Down Expand Up @@ -121,6 +121,7 @@ struct FontFacePrototypeAccessorsDeclaration {
accessor_property,
getter = font_face_readonly_attribute_getter_callback,
data = callback_data_index_value(scope, 2),
returns_promise,
enumerable
)]
loaded: (),
Expand Down Expand Up @@ -344,6 +345,13 @@ pub(in crate::context_bootstrap) fn font_face_load_callback<'s>(
}
}

pub(in crate::context_bootstrap) fn is_font_face<'s>(
scope: &mut v8::PinScope<'s, '_>,
receiver: v8::Local<'s, v8::Object>,
) -> bool {
get_private_value(scope, receiver, FONT_FACE_STATUS_SLOT).is_some()
}

fn descriptor_string_property(
scope: &mut v8::PinScope<'_, '_>,
object: Option<v8::Local<'_, v8::Object>>,
Expand Down
5 changes: 3 additions & 2 deletions moli-renderer-v8/src/context_bootstrap/style_font_template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ use super::{
font_face_set_values_callback, install_font_face_set_event_handler_accessors,
install_font_face_set_load_event_template_accessors,
install_font_face_set_template_accessors, install_font_face_template_accessors,
is_font_face,
},
specs::ConstructorSpec,
};
use moli_webapi_declare::WebApiFunctionTemplate;

#[derive(WebApiFunctionTemplate)]
#[webapi(name = "FontFace", enumerable)]
#[webapi(name = "FontFace", enumerable, receiver = is_font_face)]
struct FontFaceTemplateMethodsDeclaration {
#[webapi(method, length = 0, callback = font_face_load_callback)]
#[webapi(method, length = 0, callback = font_face_load_callback, returns_promise)]
load: (),
}

Expand Down
6 changes: 3 additions & 3 deletions moli-renderer-v8/src/native_bridge/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ struct DocumentMetadataPrototypeDeclaration {
getter = document_last_modified_getter_function
)]
last_modified: (),
#[webapi(accessor_property, getter = document_referrer_getter_function)]
#[webapi(accessor_property, getter = document_referrer_getter_function, receiver = super::receivers::document)]
referrer: (),
}

Expand Down Expand Up @@ -982,9 +982,9 @@ fn document_referrer_getter_function<'s>(
args: v8::FunctionCallbackArguments<'s>,
mut rv: v8::ReturnValue<'s, v8::Value>,
) {
let Some((runtime_ptr, handle)) = document_receiver_runtime_and_handle(scope, args.this())
let Ok((runtime_ptr, handle)) =
node_runtime_and_handle_from_object_or_detached(scope, args.this())
else {
rv.set_undefined();
return;
};
let runtime = unsafe { &*runtime_ptr };
Expand Down
8 changes: 4 additions & 4 deletions moli-renderer-v8/src/native_bridge/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1001,12 +1001,14 @@ struct HtmlElementGeometryPrototypeDeclaration {
#[webapi(
accessor_property = "offsetWidth",
enumerable,
receiver = super::receivers::html_element,
getter = node_offset_width_getter_function
)]
offset_width: (),
#[webapi(
accessor_property = "offsetHeight",
enumerable,
receiver = super::receivers::html_element,
getter = node_offset_height_getter_function
)]
offset_height: (),
Expand Down Expand Up @@ -3247,7 +3249,6 @@ fn iframe_content_document_getter_function<'s>(
let Ok((runtime_ptr, handle)) =
node_runtime_and_handle_from_object_or_detached(scope, receiver)
else {
rv.set_null();
return;
};
if iframe_is_inside_its_own_child_context_document(scope, runtime_ptr, handle) {
Expand Down Expand Up @@ -3314,7 +3315,6 @@ fn iframe_content_window_getter_function<'s>(
let Ok((runtime_ptr, handle)) =
node_runtime_and_handle_from_object_or_detached(scope, receiver)
else {
rv.set_null();
return;
};
if iframe_is_inside_its_own_child_context_document(scope, runtime_ptr, handle) {
Expand Down Expand Up @@ -3984,9 +3984,9 @@ struct HtmlIFrameElementPrototypeDeclaration {
setter_data = NullToEmptyDomStringReflection::IframeMarginWidth
)]
margin_width: (),
#[webapi(accessor_property, getter = iframe_content_document_getter_function)]
#[webapi(accessor_property, getter = iframe_content_document_getter_function, receiver = super::receivers::html_iframe_element)]
content_document: (),
#[webapi(accessor_property, getter = iframe_content_window_getter_function)]
#[webapi(accessor_property, getter = iframe_content_window_getter_function, receiver = super::receivers::html_iframe_element)]
content_window: (),
}

Expand Down
1 change: 1 addition & 0 deletions moli-renderer-v8/src/native_bridge/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub(super) mod identity;
pub(crate) mod named_access;
mod node;
pub(crate) mod pointer_lock;
pub(crate) mod receivers;
mod traversal;
mod window;

Expand Down
56 changes: 56 additions & 0 deletions moli-renderer-v8/src/native_bridge/receivers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//! Native DOM brand predicates for declarative bindings. Do not consult public
//! constructors or prototype chains: those are mutable, realm-specific JS state.

use super::node::{node_is_document, node_runtime_and_handle_from_object_or_detached};

pub(crate) fn document<'s>(
scope: &mut v8::PinScope<'s, '_>,
receiver: v8::Local<'s, v8::Object>,
) -> bool {
node_runtime_and_handle_from_object_or_detached(scope, receiver)
.ok()
.is_some_and(|(runtime, handle)| node_is_document(unsafe { &*runtime }, handle))
}

pub(crate) fn html_element<'s>(
scope: &mut v8::PinScope<'s, '_>,
receiver: v8::Local<'s, v8::Object>,
) -> bool {
node_runtime_and_handle_from_object_or_detached(scope, receiver)
.ok()
.is_some_and(|(runtime, handle)| {
unsafe { &*runtime }
.dom_host()
.node(handle)
.and_then(|node| node.as_element())
.is_some_and(|element| element.namespace() == super::document::XHTML_NS)
})
}

pub(crate) fn html_canvas_element<'s>(
scope: &mut v8::PinScope<'s, '_>,
receiver: v8::Local<'s, v8::Object>,
) -> bool {
html_element_named(scope, receiver, "canvas")
}

pub(crate) fn html_iframe_element<'s>(
scope: &mut v8::PinScope<'s, '_>,
receiver: v8::Local<'s, v8::Object>,
) -> bool {
html_element_named(scope, receiver, "iframe")
}

fn html_element_named<'s>(
scope: &mut v8::PinScope<'s, '_>,
receiver: v8::Local<'s, v8::Object>,
local_name: &str,
) -> bool {
node_runtime_and_handle_from_object_or_detached(scope, receiver)
.ok()
.is_some_and(|(runtime, handle)| {
unsafe { &*runtime }
.dom_host()
.is_html_element_named(handle, local_name)
})
}
88 changes: 38 additions & 50 deletions moli-renderer-v8/src/observer_runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ use super::{
},
util::{
callback_data_index_value, callback_data_item, context_host_ptr_from_global_bridge,
get_private_object, global_constructor_prototype, serialize_v8_array,
get_private_object, get_private_value, global_constructor_prototype, serialize_v8_array,
serialize_v8_iter_array, throw_range_error, throw_type_error, v8_string, v8str,
},
window_webidl_callback::WindowWebIdlCallbackFunctionOutcome,
Expand Down Expand Up @@ -97,31 +97,26 @@ struct MutationRecordDeclaration<'scope> {
}

#[derive(WebApiObject)]
#[webapi(interface = "IntersectionObserverEntry", data_properties, enumerable)]
#[webapi(interface = "IntersectionObserverEntry")]
struct IntersectionObserverEntryDeclaration<'scope> {
#[webapi(slot = "__moliIntersectionEntryTarget")]
target: v8::Local<'scope, v8::Value>,
#[webapi(slot = "__moliIntersectionEntryIntersecting")]
is_intersecting: bool,
#[webapi(slot = "__moliIntersectionEntryVisible")]
is_visible: bool,
#[webapi(slot = "__moliIntersectionEntryRatio")]
intersection_ratio: f64,
#[webapi(slot = "__moliIntersectionEntryBoundingRect")]
bounding_client_rect: v8::Local<'scope, v8::Value>,
#[webapi(slot = "__moliIntersectionEntryIntersectionRect")]
intersection_rect: v8::Local<'scope, v8::Value>,
#[webapi(slot = "__moliIntersectionEntryRootBounds")]
root_bounds: v8::Local<'scope, v8::Value>,
#[webapi(slot = "__moliIntersectionEntryTime")]
time: f64,
}

#[derive(WebApiObject)]
#[webapi(interface = "IntersectionObserverEntry", data_properties, enumerable)]
struct IntersectionObserverEntryInitDeclaration<'scope> {
time: f64,
root_bounds: v8::Local<'scope, v8::Value>,
bounding_client_rect: v8::Local<'scope, v8::Value>,
intersection_rect: v8::Local<'scope, v8::Value>,
target: v8::Local<'scope, v8::Value>,
is_intersecting: bool,
is_visible: bool,
intersection_ratio: f64,
}

#[derive(WebApiFunctionTemplate)]
#[webapi(name = "IntersectionObserver", enumerable)]
struct IntersectionObserverPrototypeAccessorsDeclaration {
Expand All @@ -140,7 +135,7 @@ struct IntersectionObserverPrototypeAccessorsDeclaration {
}

#[derive(WebApiFunctionTemplate)]
#[webapi(name = "IntersectionObserverEntry", enumerable)]
#[webapi(name = "IntersectionObserverEntry", enumerable, receiver = is_intersection_observer_entry)]
struct IntersectionObserverEntryPrototypeAccessorsDeclaration {
#[webapi(accessor_property, getter = intersection_observer_entry_attribute_getter_callback, data = callback_data_index_value(scope, 0))]
time: (),
Expand Down Expand Up @@ -1483,7 +1478,7 @@ fn initialize_intersection_observer_entry_from_init<'s>(
.number_value(scope)
.unwrap_or(0.0);

let _ = IntersectionObserverEntryInitDeclaration {
let _ = IntersectionObserverEntryDeclaration {
time,
root_bounds,
bounding_client_rect,
Expand Down Expand Up @@ -2518,37 +2513,30 @@ fn intersection_observer_attribute_getter_callback(
);
}

fn intersection_observer_entry_attribute_getter_callback(
scope: &mut v8::PinScope<'_, '_>,
args: v8::FunctionCallbackArguments<'_>,
mut rv: v8::ReturnValue<'_, v8::Value>,
fn is_intersection_observer_entry<'s>(
scope: &mut v8::PinScope<'s, '_>,
receiver: v8::Local<'s, v8::Object>,
) -> bool {
get_private_value(scope, receiver, "__moliIntersectionEntryTime").is_some()
}

fn intersection_observer_entry_attribute_getter_callback<'s>(
scope: &mut v8::PinScope<'s, '_>,
args: v8::FunctionCallbackArguments<'s>,
mut rv: v8::ReturnValue<'s, v8::Value>,
) {
let Some(name) = callback_data_item(
let Some(slot) = callback_data_item(
scope,
&args,
INTERSECTION_OBSERVER_ENTRY_ATTRIBUTE_NAMES,
"IntersectionObserverEntry attribute names",
INTERSECTION_OBSERVER_ENTRY_ATTRIBUTE_SLOTS,
"IntersectionObserverEntry attribute slots",
) else {
rv.set_undefined();
return;
};
// Runtime-created entries define their values as own data properties. The
// prototype getter exists for WebIDL shape and should read that own value
// without re-entering the same accessor through normal property lookup.
let key = v8str(scope, name);
let Some(descriptor) = args.this().get_own_property_descriptor(scope, key.into()) else {
rv.set_undefined();
return;
};
let Ok(descriptor) = v8::Local::<v8::Object>::try_from(descriptor) else {
rv.set_undefined();
return;
};
rv.set(
descriptor
.get(scope, v8str(scope, "value").into())
.unwrap_or_else(|| v8::undefined(scope).into()),
);
let value =
get_private_value(scope, args.this(), slot).unwrap_or_else(|| v8::undefined(scope).into());
rv.set(value);
}

const INTERSECTION_OBSERVER_ATTRIBUTE_NAMES: &[&str] = &[
Expand All @@ -2560,15 +2548,15 @@ const INTERSECTION_OBSERVER_ATTRIBUTE_NAMES: &[&str] = &[
"trackVisibility",
];

const INTERSECTION_OBSERVER_ENTRY_ATTRIBUTE_NAMES: &[&str] = &[
"time",
"rootBounds",
"boundingClientRect",
"intersectionRect",
"isIntersecting",
"isVisible",
"intersectionRatio",
"target",
const INTERSECTION_OBSERVER_ENTRY_ATTRIBUTE_SLOTS: &[&str] = &[
"__moliIntersectionEntryTime",
"__moliIntersectionEntryRootBounds",
"__moliIntersectionEntryBoundingRect",
"__moliIntersectionEntryIntersectionRect",
"__moliIntersectionEntryIntersecting",
"__moliIntersectionEntryVisible",
"__moliIntersectionEntryRatio",
"__moliIntersectionEntryTarget",
];

fn timestamp_millis() -> f64 {
Expand Down
24 changes: 16 additions & 8 deletions moli-renderer-v8/src/script_vm/tests/browser_api/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1397,6 +1397,7 @@ fn font_face_declared_slots_ignore_prototype_spoofing() {
face.__moliFontFaceStatus = 'error';
face.__moliFontFaceLoaded = Promise.resolve('ownBad');
const fake = Object.create(FontFace.prototype);
globalThis.fakeLoadedResult = 'not called';
return JSON.stringify({
values: [
face.family,
Expand All @@ -1410,13 +1411,19 @@ fn font_face_declared_slots_ignore_prototype_spoofing() {
face.status,
typeof face.loaded.then
].join('|'),
fake: [
fake.family,
fake.source,
fake.style,
fake.status,
fake.loaded
].map(value => value === undefined ? 'undefined' : String(value)).join('|'),
fake: ['family', 'source', 'style', 'status', 'loaded'].map(name => {
try {
const value = fake[name];
if (name === 'loaded' && value instanceof Promise) {
value.then(
() => fakeLoadedResult = 'resolved',
error => fakeLoadedResult = error instanceof TypeError ? 'rejected:TypeError' : error.name
);
return 'Promise';
}
return String(value);
} catch (error) { return error.name; }
}).join('|'),
descriptors: [
'family',
'style',
Expand All @@ -1438,8 +1445,9 @@ fn font_face_declared_slots_ignore_prototype_spoofing() {

assert_eq!(
result,
r#"{"values":"Changed|url(demo.woff)|italic|700|condensed|small-caps|\"kern\"|swap|loaded|function","fake":"undefined|undefined|undefined|undefined|undefined","descriptors":["family:function:get family:0:function:set family:1:true:true:false","style:function:get style:0:function:set style:1:true:true:false","weight:function:get weight:0:function:set weight:1:true:true:false","stretch:function:get stretch:0:function:set stretch:1:true:true:false","variant:function:get variant:0:function:set variant:1:true:true:false","featureSettings:function:get featureSettings:0:function:set featureSettings:1:true:true:false","display:function:get display:0:function:set display:1:true:true:false","source:function:get source:0:undefined:undefined:undefined:true:true:false","status:function:get status:0:undefined:undefined:undefined:true:true:false","loaded:function:get loaded:0:undefined:undefined:undefined:true:true:false"],"ownSlots":[]}"#
r#"{"values":"Changed|url(demo.woff)|italic|700|condensed|small-caps|\"kern\"|swap|loaded|function","fake":"TypeError|TypeError|TypeError|TypeError|Promise","descriptors":["family:function:get family:0:function:set family:1:true:true:false","style:function:get style:0:function:set style:1:true:true:false","weight:function:get weight:0:function:set weight:1:true:true:false","stretch:function:get stretch:0:function:set stretch:1:true:true:false","variant:function:get variant:0:function:set variant:1:true:true:false","featureSettings:function:get featureSettings:0:function:set featureSettings:1:true:true:false","display:function:get display:0:function:set display:1:true:true:false","source:function:get source:0:undefined:undefined:undefined:true:true:false","status:function:get status:0:undefined:undefined:undefined:true:true:false","loaded:function:get loaded:0:undefined:undefined:undefined:true:true:false"],"ownSlots":[]}"#
);
assert_eq!(vm.eval("fakeLoadedResult").unwrap(), "rejected:TypeError");
}

#[test]
Expand Down
1 change: 1 addition & 0 deletions moli-renderer-v8/src/script_vm/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15163,6 +15163,7 @@ mod script_terminal_completion;
mod streams;
mod webidl_collections;
mod webidl_fetch;
mod webidl_receivers;
mod webidl_trusted_types;
mod websocket;
mod window_execution_context;
Loading
Loading