servo / servo/html5ever

rcdom: selectedcontent lookup reads self.data, option clone never runs

Open Beginner friendly
#776 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
2.6k
Forks
288
Avg merge
2d 22h
Merged PRs (30d)
8

Description

Observed

Parsing HTML with a customizable select leaves the <selectedcontent> element empty. Node::get_a_selects_enabled_selectedcontent in rcdom/lib.rs walks the descendants of the select, but the pattern match inside the loop reads &self.data instead of &node.data (line 205 on main, line 213 in the published markup5ever_rcdom 0.39.0+unofficial). self is the select element itself, so the local_name!("selectedcontent") comparison fails on every iteration and the function always returns None. As a result the maybe_clone_an_option_into_selectedcontent callback from #719 never clones anything, whether it is invoked by the html5ever tree builder or called directly on a correctly shaped tree.

Expected

Per https://html.spec.whatwg.org/#clone-an-option-into-a-selectedcontent, closing a selected option inside a select that holds an enabled selectedcontent should replace the children of that selectedcontent with clones of the option's children. Changing the match to &node.data produces exactly that tree.

Reproducer

cargo new sc-repro && cd sc-repro
cargo add html5ever@0.39 markup5ever_rcdom@0.39

src/main.rs:

use html5ever::tendril::TendrilSink;
use html5ever::{parse_document, serialize};
use markup5ever_rcdom::{Handle, NodeData, RcDom, SerializableHandle};

fn find(h: &Handle, name: &str, out: &mut Vec<Handle>) {
    if let NodeData::Element { name: n, .. } = &h.data {
        if &*n.local == name {
            out.push(h.clone());
        }
    }
    for child in h.children.borrow().iter() {
        find(child, name, out);
    }
}

fn main() {
    let input = "<select><button><selectedcontent></selectedcontent></button>\
                 <option selected>Hello</option></select>";
    let dom = parse_document(RcDom::default(), Default::default()).one(input);
    let mut buf = Vec::new();
    let doc: SerializableHandle = dom.document.clone().into();
    serialize(&mut buf, &doc, Default::default()).unwrap();
    println!("serialized: {}", String::from_utf8(buf).unwrap());
    let mut sc = Vec::new();
    find(&dom.document, "selectedcontent", &mut sc);
    println!("selectedcontent children: {}", sc[0].children.borrow().len());
}

Output with 0.39.0:

serialized: <html><head></head><body><select><button><selectedcontent></selectedcontent></button><option selected="">Hello</option></select></body></html>
selectedcontent children: 0

With the one word fix (&node.data on the line noted above) the same program prints <selectedcontent>Hello</selectedcontent> and a child count of 1.

Scope

Every code path through maybe_clone_an_option_into_selectedcontent returns without touching the tree, so the callback introduced in #719 never runs its clone step. Any DOM built with markup5ever_rcdom 0.39.0, by parsing or by direct TreeSink calls, leaves each <selectedcontent> element with whatever children it had before the option closed.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in rcdom/lib.rs at Node::get_a_selects_enabled_selectedcontent and inspect the descendant loop described in the issue. Run the supplied cargo reproducer, then verify that the selectedcontent element contains one cloned child and serializes as expected after the fix.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
web-dev
Issue type
Bug
Difficulty
1/5
Estimated time
Under an hour
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
90/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.