From 4571cc1b3b17b3a759260bdfdb2e163576b313e7 Mon Sep 17 00:00:00 2001 From: Kingsley Yung Date: Sat, 30 Aug 2025 22:33:01 +0800 Subject: [PATCH] script: Initialize IDBCursor and IDBCursorWithValue interfaces (#38850) Testing: Update WPT test expectation Fixes: Part of #38111 --------- Signed-off-by: Kingsley Yung --- components/script/dom/idbcursor.rs | 176 ++++++++++++++++++ components/script/dom/idbcursorwithvalue.rs | 78 ++++++++ components/script/dom/mod.rs | 2 + .../script_bindings/webidls/IDBCursor.webidl | 32 ++++ .../webidls/IDBCursorWithValue.webidl | 14 ++ .../wpt/meta/IndexedDB/historical.any.js.ini | 24 --- .../wpt/meta/IndexedDB/idlharness.any.js.ini | 108 ----------- .../interface-objects/001.worker.js.ini | 6 - 8 files changed, 302 insertions(+), 138 deletions(-) create mode 100644 components/script/dom/idbcursor.rs create mode 100644 components/script/dom/idbcursorwithvalue.rs create mode 100644 components/script_bindings/webidls/IDBCursor.webidl create mode 100644 components/script_bindings/webidls/IDBCursorWithValue.webidl diff --git a/components/script/dom/idbcursor.rs b/components/script/dom/idbcursor.rs new file mode 100644 index 00000000000..c3ae488298b --- /dev/null +++ b/components/script/dom/idbcursor.rs @@ -0,0 +1,176 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use std::cell::Cell; + +use dom_struct::dom_struct; +use js::jsapi::Heap; +use js::jsval::{JSVal, UndefinedValue}; +use js::rust::MutableHandleValue; +use net_traits::indexeddb_thread::{IndexedDBKeyRange, IndexedDBKeyType}; + +use crate::dom::bindings::cell::DomRefCell; +use crate::dom::bindings::codegen::Bindings::IDBCursorBinding::{ + IDBCursorDirection, IDBCursorMethods, +}; +use crate::dom::bindings::codegen::UnionTypes::IDBObjectStoreOrIDBIndex; +use crate::dom::bindings::reflector::{Reflector, reflect_dom_object}; +use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; +use crate::dom::globalscope::GlobalScope; +use crate::dom::idbindex::IDBIndex; +use crate::dom::idbobjectstore::IDBObjectStore; +use crate::dom::idbrequest::IDBRequest; +use crate::dom::idbtransaction::IDBTransaction; +use crate::indexed_db::key_type_to_jsval; +use crate::script_runtime::{CanGc, JSContext as SafeJSContext}; + +#[derive(JSTraceable, MallocSizeOf)] +#[expect(unused)] +#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)] +pub(crate) enum ObjectStoreOrIndex { + ObjectStore(Dom), + Index(Dom), +} + +#[dom_struct] +pub(crate) struct IDBCursor { + reflector_: Reflector, + + /// + transaction: Dom, + /// + #[no_trace] + range: IndexedDBKeyRange, + /// + source: ObjectStoreOrIndex, + /// + direction: IDBCursorDirection, + /// + #[no_trace] + position: DomRefCell>, + /// + #[no_trace] + key: DomRefCell>, + /// + #[ignore_malloc_size_of = "mozjs"] + value: Heap, + /// + got_value: Cell, + /// + #[no_trace] + object_store_position: DomRefCell>, + /// + key_only: bool, + + /// + request: MutNullableDom, +} + +impl IDBCursor { + #[cfg_attr(crown, allow(crown::unrooted_must_root))] + pub(crate) fn new_inherited( + transaction: &IDBTransaction, + direction: IDBCursorDirection, + got_value: bool, + source: ObjectStoreOrIndex, + range: IndexedDBKeyRange, + key_only: bool, + ) -> IDBCursor { + IDBCursor { + reflector_: Reflector::new(), + transaction: Dom::from_ref(transaction), + range, + source, + direction, + position: DomRefCell::new(None), + key: DomRefCell::new(None), + value: Heap::default(), + got_value: Cell::new(got_value), + object_store_position: DomRefCell::new(None), + key_only, + request: Default::default(), + } + } + + #[expect(unused)] + #[cfg_attr(crown, allow(crown::unrooted_must_root))] + #[allow(clippy::too_many_arguments)] + pub(crate) fn new( + global: &GlobalScope, + transaction: &IDBTransaction, + direction: IDBCursorDirection, + got_value: bool, + source: ObjectStoreOrIndex, + range: IndexedDBKeyRange, + key_only: bool, + can_gc: CanGc, + ) -> DomRoot { + reflect_dom_object( + Box::new(IDBCursor::new_inherited( + transaction, + direction, + got_value, + source, + range, + key_only, + )), + global, + can_gc, + ) + } + + pub(crate) fn value(&self, mut out: MutableHandleValue) { + out.set(self.value.get()); + } + + /// + pub(crate) fn effective_key(&self) -> Option { + match &self.source { + ObjectStoreOrIndex::ObjectStore(_) => self.position.borrow().clone(), + ObjectStoreOrIndex::Index(_) => self.object_store_position.borrow().clone(), + } + } +} + +impl IDBCursorMethods for IDBCursor { + /// + fn Source(&self) -> IDBObjectStoreOrIDBIndex { + match &self.source { + ObjectStoreOrIndex::ObjectStore(source) => { + IDBObjectStoreOrIDBIndex::IDBObjectStore(source.as_rooted()) + }, + ObjectStoreOrIndex::Index(source) => { + IDBObjectStoreOrIDBIndex::IDBIndex(source.as_rooted()) + }, + } + } + + /// + fn Direction(&self) -> IDBCursorDirection { + self.direction + } + + /// + fn Key(&self, cx: SafeJSContext, mut value: MutableHandleValue) { + match self.key.borrow().as_ref() { + Some(key) => key_type_to_jsval(cx, key, value), + None => value.set(UndefinedValue()), + } + } + + /// + fn PrimaryKey(&self, cx: SafeJSContext, mut value: MutableHandleValue) { + match self.effective_key() { + Some(effective_key) => key_type_to_jsval(cx, &effective_key, value), + None => value.set(UndefinedValue()), + } + } + + /// + fn Request(&self) -> DomRoot { + self.request + .get() + .expect("IDBCursor.request should be set when cursor is opened") + } +} diff --git a/components/script/dom/idbcursorwithvalue.rs b/components/script/dom/idbcursorwithvalue.rs new file mode 100644 index 00000000000..818a974402f --- /dev/null +++ b/components/script/dom/idbcursorwithvalue.rs @@ -0,0 +1,78 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use dom_struct::dom_struct; +use js::rust::MutableHandleValue; +use net_traits::indexeddb_thread::IndexedDBKeyRange; + +use crate::dom::bindings::codegen::Bindings::IDBCursorBinding::IDBCursorDirection; +use crate::dom::bindings::codegen::Bindings::IDBCursorWithValueBinding::IDBCursorWithValueMethods; +use crate::dom::bindings::reflector::reflect_dom_object; +use crate::dom::bindings::root::DomRoot; +use crate::dom::globalscope::GlobalScope; +use crate::dom::idbcursor::{IDBCursor, ObjectStoreOrIndex}; +use crate::dom::idbtransaction::IDBTransaction; +use crate::script_runtime::{CanGc, JSContext as SafeJSContext}; + +#[dom_struct] +pub(crate) struct IDBCursorWithValue { + cursor: IDBCursor, +} + +impl IDBCursorWithValue { + #[cfg_attr(crown, allow(crown::unrooted_must_root))] + fn new_inherited( + transaction: &IDBTransaction, + direction: IDBCursorDirection, + got_value: bool, + source: ObjectStoreOrIndex, + range: IndexedDBKeyRange, + key_only: bool, + ) -> IDBCursorWithValue { + IDBCursorWithValue { + cursor: IDBCursor::new_inherited( + transaction, + direction, + got_value, + source, + range, + key_only, + ), + } + } + + #[expect(unused)] + #[cfg_attr(crown, allow(crown::unrooted_must_root))] + #[allow(clippy::too_many_arguments)] + pub(crate) fn new( + global: &GlobalScope, + transaction: &IDBTransaction, + direction: IDBCursorDirection, + got_value: bool, + source: ObjectStoreOrIndex, + range: IndexedDBKeyRange, + key_only: bool, + can_gc: CanGc, + ) -> DomRoot { + reflect_dom_object( + Box::new(IDBCursorWithValue::new_inherited( + transaction, + direction, + got_value, + source, + range, + key_only, + )), + global, + can_gc, + ) + } +} + +impl IDBCursorWithValueMethods for IDBCursorWithValue { + /// + fn Value(&self, _cx: SafeJSContext, value: MutableHandleValue) { + self.cursor.value(value); + } +} diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index 20011fac74a..9259e3e0a84 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -407,6 +407,8 @@ pub(crate) mod htmltrackelement; pub(crate) mod htmlulistelement; pub(crate) mod htmlunknownelement; pub(crate) mod htmlvideoelement; +pub(crate) mod idbcursor; +pub(crate) mod idbcursorwithvalue; pub(crate) mod idbdatabase; pub(crate) mod idbfactory; pub(crate) mod idbindex; diff --git a/components/script_bindings/webidls/IDBCursor.webidl b/components/script_bindings/webidls/IDBCursor.webidl new file mode 100644 index 00000000000..93ec491e785 --- /dev/null +++ b/components/script_bindings/webidls/IDBCursor.webidl @@ -0,0 +1,32 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +/* + * The origin of this IDL file is + * https://w3c.github.io/IndexedDB/#idbcursor + * + */ + +// https://w3c.github.io/IndexedDB/#idbcursor +[Pref="dom_indexeddb_enabled", Exposed=(Window,Worker)] +interface IDBCursor { + readonly attribute (IDBObjectStore or IDBIndex) source; + readonly attribute IDBCursorDirection direction; + readonly attribute any key; + readonly attribute any primaryKey; + [SameObject] readonly attribute IDBRequest request; + + // undefined advance([EnforceRange] unsigned long count); + // undefined continue(optional any key); + // undefined continuePrimaryKey(any key, any primaryKey); + + // [NewObject] IDBRequest update(any value); + // [NewObject] IDBRequest delete(); +}; + +enum IDBCursorDirection { + "next", + "nextunique", + "prev", + "prevunique" +}; diff --git a/components/script_bindings/webidls/IDBCursorWithValue.webidl b/components/script_bindings/webidls/IDBCursorWithValue.webidl new file mode 100644 index 00000000000..cb5eea84c93 --- /dev/null +++ b/components/script_bindings/webidls/IDBCursorWithValue.webidl @@ -0,0 +1,14 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +/* + * The origin of this IDL file is + * https://w3c.github.io/IndexedDB/#idbcursorwithvalue + * + */ + +// https://w3c.github.io/IndexedDB/#idbcursorwithvalue +[Pref="dom_indexeddb_enabled", Exposed=(Window,Worker)] +interface IDBCursorWithValue : IDBCursor { + readonly attribute any value; +}; diff --git a/tests/wpt/meta/IndexedDB/historical.any.js.ini b/tests/wpt/meta/IndexedDB/historical.any.js.ini index ba838dbce10..e033d1b4b45 100644 --- a/tests/wpt/meta/IndexedDB/historical.any.js.ini +++ b/tests/wpt/meta/IndexedDB/historical.any.js.ini @@ -2,32 +2,8 @@ expected: ERROR [historical.any.html] - ["NEXT" should not be supported on IDBCursor.] - expected: FAIL - - ["NEXT_NO_DUPLICATE" should not be supported on IDBCursor.] - expected: FAIL - - ["PREV" should not be supported on IDBCursor.] - expected: FAIL - - ["PREV_NO_DUPLICATE" should not be supported on IDBCursor.] - expected: FAIL - [historical.any.worker.html] - ["NEXT" should not be supported on IDBCursor.] - expected: FAIL - - ["NEXT_NO_DUPLICATE" should not be supported on IDBCursor.] - expected: FAIL - - ["PREV" should not be supported on IDBCursor.] - expected: FAIL - - ["PREV_NO_DUPLICATE" should not be supported on IDBCursor.] - expected: FAIL - [historical.any.sharedworker.html] expected: ERROR diff --git a/tests/wpt/meta/IndexedDB/idlharness.any.js.ini b/tests/wpt/meta/IndexedDB/idlharness.any.js.ini index 6ea65643ea2..8b18802cd8a 100644 --- a/tests/wpt/meta/IndexedDB/idlharness.any.js.ini +++ b/tests/wpt/meta/IndexedDB/idlharness.any.js.ini @@ -59,39 +59,6 @@ [IDBIndex interface: operation openKeyCursor(optional any, optional IDBCursorDirection)] expected: FAIL - [IDBCursor interface: existence and properties of interface object] - expected: FAIL - - [IDBCursor interface object length] - expected: FAIL - - [IDBCursor interface object name] - expected: FAIL - - [IDBCursor interface: existence and properties of interface prototype object] - expected: FAIL - - [IDBCursor interface: existence and properties of interface prototype object's "constructor" property] - expected: FAIL - - [IDBCursor interface: existence and properties of interface prototype object's @@unscopables property] - expected: FAIL - - [IDBCursor interface: attribute source] - expected: FAIL - - [IDBCursor interface: attribute direction] - expected: FAIL - - [IDBCursor interface: attribute key] - expected: FAIL - - [IDBCursor interface: attribute primaryKey] - expected: FAIL - - [IDBCursor interface: attribute request] - expected: FAIL - [IDBCursor interface: operation advance(unsigned long)] expected: FAIL @@ -107,27 +74,6 @@ [IDBCursor interface: operation delete()] expected: FAIL - [IDBCursorWithValue interface: existence and properties of interface object] - expected: FAIL - - [IDBCursorWithValue interface object length] - expected: FAIL - - [IDBCursorWithValue interface object name] - expected: FAIL - - [IDBCursorWithValue interface: existence and properties of interface prototype object] - expected: FAIL - - [IDBCursorWithValue interface: existence and properties of interface prototype object's "constructor" property] - expected: FAIL - - [IDBCursorWithValue interface: existence and properties of interface prototype object's @@unscopables property] - expected: FAIL - - [IDBCursorWithValue interface: attribute value] - expected: FAIL - [IDBTransaction interface: attribute durability] expected: FAIL @@ -229,39 +175,6 @@ [IDBIndex interface: operation openKeyCursor(optional any, optional IDBCursorDirection)] expected: FAIL - [IDBCursor interface: existence and properties of interface object] - expected: FAIL - - [IDBCursor interface object length] - expected: FAIL - - [IDBCursor interface object name] - expected: FAIL - - [IDBCursor interface: existence and properties of interface prototype object] - expected: FAIL - - [IDBCursor interface: existence and properties of interface prototype object's "constructor" property] - expected: FAIL - - [IDBCursor interface: existence and properties of interface prototype object's @@unscopables property] - expected: FAIL - - [IDBCursor interface: attribute source] - expected: FAIL - - [IDBCursor interface: attribute direction] - expected: FAIL - - [IDBCursor interface: attribute key] - expected: FAIL - - [IDBCursor interface: attribute primaryKey] - expected: FAIL - - [IDBCursor interface: attribute request] - expected: FAIL - [IDBCursor interface: operation advance(unsigned long)] expected: FAIL @@ -277,27 +190,6 @@ [IDBCursor interface: operation delete()] expected: FAIL - [IDBCursorWithValue interface: existence and properties of interface object] - expected: FAIL - - [IDBCursorWithValue interface object length] - expected: FAIL - - [IDBCursorWithValue interface object name] - expected: FAIL - - [IDBCursorWithValue interface: existence and properties of interface prototype object] - expected: FAIL - - [IDBCursorWithValue interface: existence and properties of interface prototype object's "constructor" property] - expected: FAIL - - [IDBCursorWithValue interface: existence and properties of interface prototype object's @@unscopables property] - expected: FAIL - - [IDBCursorWithValue interface: attribute value] - expected: FAIL - [IDBTransaction interface: attribute durability] expected: FAIL diff --git a/tests/wpt/meta/workers/semantics/interface-objects/001.worker.js.ini b/tests/wpt/meta/workers/semantics/interface-objects/001.worker.js.ini index e71803ea330..eac399d068b 100644 --- a/tests/wpt/meta/workers/semantics/interface-objects/001.worker.js.ini +++ b/tests/wpt/meta/workers/semantics/interface-objects/001.worker.js.ini @@ -4,9 +4,3 @@ [The CanvasPath interface object should be exposed.] expected: FAIL - - [The IDBCursor interface object should be exposed.] - expected: FAIL - - [The IDBCursorWithValue interface object should be exposed.] - expected: FAIL