Repository: servo/servo
File: components/script/dom/node.rs (Rust)

Code before:
                &Some(node),
                &[],
                old_next_sibling.as_deref(),
            ));

            let removed = [node];
            let mutation = LazyCell::new(|| Mutation::ChildList {
                added: None,
                removed: Some(&removed),
                prev: old_previous_sibling.as_deref(),
                next: old_next_sibling.as_deref(),
            });
            MutationObserver::queue_a_mutation_record(parent, mutation);
        }
        parent.owner_doc().remove_script_and_layout_blocker();
    }

    /// Ensure that for styles, we clone the already-parsed property declaration block.
    /// This does two things:
    /// 1. it uses the same fast-path as CSSStyleDeclaration
    /// 2. it also avoids the CSP checks when cloning (it shouldn't run any when cloning
    ///    existing valid attributes)
    fn compute_attribute_value_with_style_fast_path(attr: &Dom<Attr>, elem: &Element) -> AttrValue {
        if *attr.local_name() == local_name!("style") {
            if let Some(ref pdb) = *elem.style_attribute().borrow() {
                return AttrValue::Declaration((**attr.value()).to_owned(), pdb.clone());
            }
        }

        attr.value().clone()
    }

    /// <https://dom.spec.whatwg.org/#concept-node-clone>
    pub(crate) fn clone(
        node: &Node,
        maybe_doc: Option<&Document>,
        clone_children: CloneChildrenFlag,
        can_gc: CanGc,
    ) -> DomRoot<Node> {
        // Step 1. If document is not given, let document be node’s node document.
        let document = match maybe_doc {
            Some(doc) => DomRoot::from_ref(doc),
            None => node.owner_doc(),
        };

        // Step 2. / Step 3.
        // XXXabinader: clone() for each node as trait?
        let copy: DomRoot<Node> = match node.type_id() {
            NodeTypeId::DocumentType => {
                let doctype = node.downcast::<DocumentType>().unwrap();
                let doctype = DocumentType::new(

Review comment (bug):
@Loirooriol I think you are familiar with `PropertyDeclarationBlock`, aren't you? It seems that `tests/wpt/tests/css/css-fonts/variations/font-weight-matching.html` fails on cloning nodes, since the font-face declarations aren't updated. They appear to use the old declarations.

Unfortunately I don't know all inner details of Stylo here and how I should reason about this. I looked at `CSSStyleOwner::mutate_associated_block` and how I could do it, but unfortunately I don't see how I can clone a declaration.

I have tried the following to see if that would help, but it results in the same:

```rust
let document = elem.owner_document();
let guard = document.style_shared_lock().read();
let mut serialization = String::new();
pdb.read_with(&guard).to_css(&mut serialization).unwrap();
return AttrValue::Declaration(serialization, pdb.clone());
```

Can you help me out in what I am doing wrong?

Code after:
                removed: Some(&removed),
                prev: old_previous_sibling.as_deref(),
                next: old_next_sibling.as_deref(),
            });
            MutationObserver::queue_a_mutation_record(parent, mutation);
        }
        parent.owner_doc().remove_script_and_layout_blocker();
    }

    /// Ensure that for styles, we clone the already-parsed property declaration block.
    /// This does two things:
    /// 1. it uses the same fast-path as CSSStyleDeclaration
    /// 2. it also avoids the CSP checks when cloning (it shouldn't run any when cloning
    ///    existing valid attributes)
    fn compute_attribute_value_with_style_fast_path(attr: &Dom<Attr>, elem: &Element) -> AttrValue {
        if *attr.local_name() == local_name!("style") {
            if let Some(ref pdb) = *elem.style_attribute().borrow() {
                let document = elem.owner_document();
                let shared_lock = document.style_shared_lock();
                let new_pdb = pdb.read_with(&shared_lock.read()).clone();
                return AttrValue::Declaration(
                    (**attr.value()).to_owned(),
                    Arc::new(shared_lock.wrap(new_pdb)),
                );
            }
        }

        attr.value().clone()
    }

    /// <https://dom.spec.whatwg.org/#concept-node-clone>
    pub(crate) fn clone(
        node: &Node,
        maybe_doc: Option<&Document>,
        clone_children: CloneChildrenFlag,
        can_gc: CanGc,
    ) -> DomRoot<Node> {
        // Step 1. If document is not given, let document be node’s node document.
        let document = match maybe_doc {
            Some(doc) => DomRoot::from_ref(doc),
            None => node.owner_doc(),
        };

        // Step 2. / Step 3.
        // XXXabinader: clone() for each node as trait?
        let copy: DomRoot<Node> = match node.type_id() {
            NodeTypeId::DocumentType => {
                let doctype = node.downcast::<DocumentType>().unwrap();
                let doctype = DocumentType::new(
                    doctype.name().clone(),
                    Some(doctype.public_id().clone()),