Browse Source

Merge branch 'master' of github.com:DioxusLabs/dioxus

Jonathan Kelley 2 years ago
parent
commit
92be7f990b

+ 1 - 0
packages/core/Cargo.toml

@@ -41,6 +41,7 @@ serde = { version = "1", features = ["derive"], optional = true }
 tokio = { version = "1", features = ["full"] }
 dioxus = { path = "../dioxus" }
 pretty_assertions = "1.3.0"
+rand = "0.8.5"
 
 [features]
 default = []

+ 15 - 4
packages/core/src/arena.rs

@@ -1,3 +1,5 @@
+use std::ptr::NonNull;
+
 use crate::{
     nodes::RenderReturn, nodes::VNode, virtual_dom::VirtualDom, AttributeValue, DynamicNode,
     ScopeId,
@@ -17,7 +19,7 @@ pub(crate) struct ElementRef {
     pub path: ElementPath,
 
     // The actual template
-    pub template: *const VNode<'static>,
+    pub template: Option<NonNull<VNode<'static>>>,
 }
 
 #[derive(Clone, Copy)]
@@ -27,9 +29,9 @@ pub enum ElementPath {
 }
 
 impl ElementRef {
-    pub(crate) fn null() -> Self {
+    pub(crate) fn none() -> Self {
         Self {
-            template: std::ptr::null_mut(),
+            template: None,
             path: ElementPath::Root(0),
         }
     }
@@ -44,12 +46,21 @@ impl VirtualDom {
         self.next_reference(template, ElementPath::Root(path))
     }
 
+    pub(crate) fn next_null(&mut self) -> ElementId {
+        let entry = self.elements.vacant_entry();
+        let id = entry.key();
+
+        entry.insert(ElementRef::none());
+        ElementId(id)
+    }
+
     fn next_reference(&mut self, template: &VNode, path: ElementPath) -> ElementId {
         let entry = self.elements.vacant_entry();
         let id = entry.key();
 
         entry.insert(ElementRef {
-            template: template as *const _ as *mut _,
+            // We know this is non-null because it comes from a reference
+            template: Some(unsafe { NonNull::new_unchecked(template as *const _ as *mut _) }),
             path,
         });
         ElementId(id)

+ 22 - 9
packages/core/src/diff.rs

@@ -42,7 +42,7 @@ impl<'b> VirtualDom {
                 // Just move over the placeholder
                 (Aborted(l), Aborted(r)) => r.id.set(l.id.get()),
 
-                // Becomes async, do nothing while we ait
+                // Becomes async, do nothing while we wait
                 (Ready(_nodes), Pending(_fut)) => self.diff_ok_to_async(_nodes, scope),
 
                 // Placeholder becomes something
@@ -65,8 +65,26 @@ impl<'b> VirtualDom {
         //
     }
 
-    fn diff_ok_to_err(&mut self, _l: &'b VNode<'b>, _p: &'b VPlaceholder) {
-        todo!()
+    fn diff_ok_to_err(&mut self, l: &'b VNode<'b>, p: &'b VPlaceholder) {
+        let id = self.next_null();
+        p.id.set(Some(id));
+        self.mutations.push(Mutation::CreatePlaceholder { id });
+
+        let pre_edits = self.mutations.edits.len();
+
+        self.remove_node(l, true);
+
+        // We should always have a remove mutation
+        // Eventually we don't want to generate placeholders, so this might not be true. But it's true today
+        assert!(self.mutations.edits.len() > pre_edits);
+
+        // We want to optimize the replace case to use one less mutation if possible
+        // Since mutations are done in reverse, the last node removed will be the first in the stack
+        // Instead of *just* removing it, we can use the replace mutation
+        match self.mutations.edits.pop().unwrap() {
+            Mutation::Remove { id } => self.mutations.push(Mutation::ReplaceWith { id, m: 1 }),
+            _ => panic!("Expected remove mutation from remove_node"),
+        };
     }
 
     fn diff_node(&mut self, left_template: &'b VNode<'b>, right_template: &'b VNode<'b>) {
@@ -905,12 +923,7 @@ impl<'b> VirtualDom {
 
         match unsafe { self.scopes[scope.0].root_node().extend_lifetime_ref() } {
             RenderReturn::Ready(t) => self.remove_node(t, gen_muts),
-            RenderReturn::Aborted(t) => {
-                if let Some(id) = t.id.get() {
-                    self.try_reclaim(id);
-                }
-                return;
-            }
+            RenderReturn::Aborted(placeholder) => self.remove_placeholder(placeholder, gen_muts),
             _ => todo!(),
         };
 

+ 2 - 2
packages/core/src/virtual_dom.rs

@@ -282,7 +282,7 @@ impl VirtualDom {
         root.provide_context(Rc::new(ErrorBoundary::new(ScopeId(0))));
 
         // the root element is always given element ID 0 since it's the container for the entire tree
-        dom.elements.insert(ElementRef::null());
+        dom.elements.insert(ElementRef::none());
 
         dom
     }
@@ -387,7 +387,7 @@ impl VirtualDom {
         // Loop through each dynamic attribute in this template before moving up to the template's parent.
         while let Some(el_ref) = parent_path {
             // safety: we maintain references of all vnodes in the element slab
-            let template = unsafe { &*el_ref.template };
+            let template = unsafe { el_ref.template.unwrap().as_ref() };
             let node_template = template.template.get();
             let target_path = el_ref.path;
 

+ 305 - 0
packages/core/tests/fuzzing.rs

@@ -0,0 +1,305 @@
+use dioxus::prelude::Props;
+use dioxus_core::*;
+use std::cell::Cell;
+
+fn random_ns() -> Option<&'static str> {
+    let namespace = rand::random::<u8>() % 2;
+    match namespace {
+        0 => None,
+        1 => Some(Box::leak(
+            format!("ns{}", rand::random::<usize>()).into_boxed_str(),
+        )),
+        _ => unreachable!(),
+    }
+}
+
+fn create_random_attribute(attr_idx: &mut usize) -> TemplateAttribute<'static> {
+    match rand::random::<u8>() % 2 {
+        0 => TemplateAttribute::Static {
+            name: Box::leak(format!("attr{}", rand::random::<usize>()).into_boxed_str()),
+            value: Box::leak(format!("value{}", rand::random::<usize>()).into_boxed_str()),
+            namespace: random_ns(),
+        },
+        1 => TemplateAttribute::Dynamic {
+            id: {
+                let old_idx = *attr_idx;
+                *attr_idx += 1;
+                old_idx
+            },
+        },
+        _ => unreachable!(),
+    }
+}
+
+fn create_random_template_node(
+    dynamic_node_types: &mut Vec<DynamicNodeType>,
+    template_idx: &mut usize,
+    attr_idx: &mut usize,
+    depth: usize,
+) -> TemplateNode<'static> {
+    match rand::random::<u8>() % 4 {
+        0 => {
+            let attrs = {
+                let attrs: Vec<_> = (0..(rand::random::<usize>() % 10))
+                    .map(|_| create_random_attribute(attr_idx))
+                    .collect();
+                Box::leak(attrs.into_boxed_slice())
+            };
+            TemplateNode::Element {
+                tag: Box::leak(format!("tag{}", rand::random::<usize>()).into_boxed_str()),
+                namespace: random_ns(),
+                attrs,
+                children: {
+                    if depth > 4 {
+                        &[]
+                    } else {
+                        let children: Vec<_> = (0..(rand::random::<usize>() % 3))
+                            .map(|_| {
+                                create_random_template_node(
+                                    dynamic_node_types,
+                                    template_idx,
+                                    attr_idx,
+                                    depth + 1,
+                                )
+                            })
+                            .collect();
+                        Box::leak(children.into_boxed_slice())
+                    }
+                },
+            }
+        }
+        1 => TemplateNode::Text {
+            text: Box::leak(format!("{}", rand::random::<usize>()).into_boxed_str()),
+        },
+        2 => TemplateNode::DynamicText {
+            id: {
+                let old_idx = *template_idx;
+                *template_idx += 1;
+                dynamic_node_types.push(DynamicNodeType::Text);
+                old_idx
+            },
+        },
+        3 => TemplateNode::Dynamic {
+            id: {
+                let old_idx = *template_idx;
+                *template_idx += 1;
+                dynamic_node_types.push(DynamicNodeType::Other);
+                old_idx
+            },
+        },
+        _ => unreachable!(),
+    }
+}
+
+fn generate_paths(
+    node: &TemplateNode<'static>,
+    current_path: &[u8],
+    node_paths: &mut Vec<Vec<u8>>,
+    attr_paths: &mut Vec<Vec<u8>>,
+) {
+    match node {
+        TemplateNode::Element { children, attrs, .. } => {
+            for attr in *attrs {
+                match attr {
+                    TemplateAttribute::Static { .. } => {}
+                    TemplateAttribute::Dynamic { .. } => {
+                        attr_paths.push(current_path.to_vec());
+                    }
+                }
+            }
+            for (i, child) in children.iter().enumerate() {
+                let mut current_path = current_path.to_vec();
+                current_path.push(i as u8);
+                generate_paths(child, &current_path, node_paths, attr_paths);
+            }
+        }
+        TemplateNode::Text { .. } => {}
+        TemplateNode::DynamicText { .. } => {
+            node_paths.push(current_path.to_vec());
+        }
+        TemplateNode::Dynamic { .. } => {
+            node_paths.push(current_path.to_vec());
+        }
+    }
+}
+
+enum DynamicNodeType {
+    Text,
+    Other,
+}
+
+fn create_random_template(name: &'static str) -> (Template<'static>, Vec<DynamicNodeType>) {
+    let mut dynamic_node_type = Vec::new();
+    let mut template_idx = 0;
+    let mut attr_idx = 0;
+    let roots = (0..(1 + rand::random::<usize>() % 5))
+        .map(|_| {
+            create_random_template_node(&mut dynamic_node_type, &mut template_idx, &mut attr_idx, 0)
+        })
+        .collect::<Vec<_>>();
+    assert!(!roots.is_empty());
+    let roots = Box::leak(roots.into_boxed_slice());
+    let mut node_paths = Vec::new();
+    let mut attr_paths = Vec::new();
+    for (i, root) in roots.iter().enumerate() {
+        generate_paths(root, &[i as u8], &mut node_paths, &mut attr_paths);
+    }
+    let node_paths = Box::leak(
+        node_paths
+            .into_iter()
+            .map(|v| &*Box::leak(v.into_boxed_slice()))
+            .collect::<Vec<_>>()
+            .into_boxed_slice(),
+    );
+    let attr_paths = Box::leak(
+        attr_paths
+            .into_iter()
+            .map(|v| &*Box::leak(v.into_boxed_slice()))
+            .collect::<Vec<_>>()
+            .into_boxed_slice(),
+    );
+    (
+        Template { name, roots, node_paths, attr_paths },
+        dynamic_node_type,
+    )
+}
+
+fn create_random_dynamic_node(cx: &ScopeState, depth: usize) -> DynamicNode {
+    let range = if depth > 3 { 1 } else { 3 };
+    match rand::random::<u8>() % range {
+        0 => DynamicNode::Placeholder(Default::default()),
+        1 => cx.make_node((0..(rand::random::<u8>() % 5)).map(|_| VNode {
+            key: None,
+            parent: Default::default(),
+            template: Cell::new(Template {
+                name: concat!(file!(), ":", line!(), ":", column!(), ":0"),
+                roots: &[TemplateNode::Dynamic { id: 0 }],
+                node_paths: &[&[0]],
+                attr_paths: &[],
+            }),
+            root_ids: Default::default(),
+            dynamic_nodes: cx.bump().alloc([cx.component(
+                create_random_element,
+                DepthProps { depth, root: false },
+                "create_random_element",
+            )]),
+            dynamic_attrs: &[],
+        })),
+        2 => cx.component(
+            create_random_element,
+            DepthProps { depth, root: false },
+            "create_random_element",
+        ),
+        _ => unreachable!(),
+    }
+}
+
+fn create_random_dynamic_attr(cx: &ScopeState) -> Attribute {
+    let value = match rand::random::<u8>() % 6 {
+        0 => AttributeValue::Text(Box::leak(
+            format!("{}", rand::random::<usize>()).into_boxed_str(),
+        )),
+        1 => AttributeValue::Float(rand::random()),
+        2 => AttributeValue::Int(rand::random()),
+        3 => AttributeValue::Bool(rand::random()),
+        4 => cx.any_value(rand::random::<usize>()),
+        5 => AttributeValue::None,
+        // Listener(RefCell<Option<ListenerCb<'a>>>),
+        _ => unreachable!(),
+    };
+    Attribute {
+        name: Box::leak(format!("attr{}", rand::random::<usize>()).into_boxed_str()),
+        value,
+        namespace: random_ns(),
+        mounted_element: Default::default(),
+        volatile: rand::random(),
+    }
+}
+
+static mut TEMPLATE_COUNT: usize = 0;
+
+#[derive(PartialEq, Props)]
+struct DepthProps {
+    depth: usize,
+    root: bool,
+}
+
+fn create_random_element(cx: Scope<DepthProps>) -> Element {
+    cx.needs_update();
+    let range = if cx.props.root { 2 } else { 3 };
+    let node = match rand::random::<usize>() % range {
+        0 | 1 => {
+            let (template, dynamic_node_types) = create_random_template(Box::leak(
+                format!(
+                    "{}{}",
+                    concat!(file!(), ":", line!(), ":", column!(), ":"),
+                    {
+                        unsafe {
+                            let old = TEMPLATE_COUNT;
+                            TEMPLATE_COUNT += 1;
+                            old
+                        }
+                    }
+                )
+                .into_boxed_str(),
+            ));
+            println!("{template:#?}");
+            let node = VNode {
+                key: None,
+                parent: None,
+                template: Cell::new(template),
+                root_ids: Default::default(),
+                dynamic_nodes: {
+                    let dynamic_nodes: Vec<_> = dynamic_node_types
+                        .iter()
+                        .map(|ty| match ty {
+                            DynamicNodeType::Text => DynamicNode::Text(VText {
+                                value: Box::leak(
+                                    format!("{}", rand::random::<usize>()).into_boxed_str(),
+                                ),
+                                id: Default::default(),
+                            }),
+                            DynamicNodeType::Other => {
+                                create_random_dynamic_node(cx, cx.props.depth + 1)
+                            }
+                        })
+                        .collect();
+                    cx.bump().alloc(dynamic_nodes)
+                },
+                dynamic_attrs: cx.bump().alloc(
+                    (0..template.attr_paths.len())
+                        .map(|_| create_random_dynamic_attr(cx))
+                        .collect::<Vec<_>>(),
+                ),
+            };
+            Some(node)
+        }
+        _ => None,
+    };
+    println!("{node:#?}");
+    node
+}
+
+// test for panics when creating random nodes and templates
+#[test]
+fn create() {
+    for _ in 0..100 {
+        let mut vdom =
+            VirtualDom::new_with_props(create_random_element, DepthProps { depth: 0, root: true });
+        let _ = vdom.rebuild();
+    }
+}
+
+// test for panics when diffing random nodes
+// This test will change the template every render which is not very realistic, but it helps stress the system
+#[test]
+fn diff() {
+    for _ in 0..10 {
+        let mut vdom =
+            VirtualDom::new_with_props(create_random_element, DepthProps { depth: 0, root: true });
+        let _ = vdom.rebuild();
+        for _ in 0..10 {
+            let _ = vdom.render_immediate();
+        }
+    }
+}

+ 12 - 12
packages/html/src/elements.rs

@@ -294,7 +294,7 @@ builder_constructors! {
         rel: LinkType DEFAULT,
         sizes: String DEFAULT, // FIXME
         title: String DEFAULT, // FIXME
-        r#type: Mime DEFAULT,
+        r#type: Mime "type",
         integrity: String DEFAULT,
     };
 
@@ -312,7 +312,7 @@ builder_constructors! {
     /// [`<style>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/style)
     /// element.
     style None {
-        r#type: Mime DEFAULT,
+        r#type: Mime "type",
         media: String DEFAULT, // FIXME media query
         nonce: Nonce DEFAULT,
         title: String DEFAULT, // FIXME
@@ -517,7 +517,7 @@ builder_constructors! {
     ol None {
         reversed: Bool DEFAULT,
         start: isize DEFAULT,
-        r#type: OrderedListType DEFAULT,
+        r#type: OrderedListType "type",
     };
 
     /// Build a
@@ -546,7 +546,7 @@ builder_constructors! {
         href: Uri DEFAULT,
         hreflang: LanguageTag DEFAULT,
         target: Target DEFAULT,
-        r#type: Mime DEFAULT,
+        r#type: Mime "type",
         // ping: SpacedList<Uri>,
         // rel: SpacedList<LinkType>,
         ping: SpacedList DEFAULT,
@@ -737,7 +737,7 @@ builder_constructors! {
         muted: Bool DEFAULT,
         preload: Preload DEFAULT,
         src: Uri DEFAULT,
-        r#loop: Bool DEFAULT,
+        r#loop: Bool "loop",
     };
 
     /// Build a
@@ -783,7 +783,7 @@ builder_constructors! {
         controls: Bool DEFAULT,
         crossorigin: CrossOrigin DEFAULT,
         height: usize DEFAULT,
-        r#loop: Bool DEFAULT,
+        r#loop: Bool "loop",
         muted: Bool DEFAULT,
         preload: Preload DEFAULT,
         playsinline: Bool DEFAULT,
@@ -801,7 +801,7 @@ builder_constructors! {
     embed None {
         height: usize DEFAULT,
         src: Uri DEFAULT,
-        r#type: Mime DEFAULT,
+        r#type: Mime "type",
         width: usize DEFAULT,
     };
 
@@ -819,13 +819,13 @@ builder_constructors! {
         srcdoc: Uri DEFAULT,
         width: usize DEFAULT,
 
-        marginWidth: String DEFAULT,
+        margin_width: String "marginWidth",
         align: String DEFAULT,
         longdesc: String DEFAULT,
 
         scrolling: String DEFAULT,
-        marginHeight: String DEFAULT,
-        frameBorder: String DEFAULT,
+        margin_height: String "marginHeight",
+        frame_border: String "frameBorder",
         // sandbox: SpacedSet<Sandbox>,
     };
 
@@ -837,7 +837,7 @@ builder_constructors! {
         form: Id DEFAULT,
         height: usize DEFAULT,
         name: Id DEFAULT,
-        r#type: Mime DEFAULT,
+        r#type: Mime "type",
         typemustmatch: Bool DEFAULT,
         usemap: String DEFAULT, // TODO should be a fragment starting with '#'
         width: usize DEFAULT,
@@ -861,7 +861,7 @@ builder_constructors! {
     /// element.
     source None {
         src: Uri DEFAULT,
-        r#type: Mime DEFAULT,
+        r#type: Mime "type",
     };
 
 

+ 62 - 62
packages/html/src/global_attributes.rs

@@ -1622,22 +1622,22 @@ trait_methods! {
     ascent: "ascent";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/attributeName>
-    attributeName: "attributeName";
+    attribute_name: "attributeName";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/attributeType>
-    attributeType: "attributeType";
+    attribute_type: "attributeType";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/azimuth>
     azimuth: "azimuth";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/baseFrequency>
-    baseFrequency: "baseFrequency";
+    base_frequency: "baseFrequency";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/baseline-shift>
     baseline_shift: "baseline-shift";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/baseProfile>
-    baseProfile: "baseProfile";
+    base_profile: "baseProfile";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/bbox>
     bbox: "bbox";
@@ -1652,7 +1652,7 @@ trait_methods! {
     by: "by";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/calcMode>
-    calcMode: "calcMode";
+    calc_mode: "calcMode";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/cap-height>
     cap_height: "cap-height";
@@ -1664,7 +1664,7 @@ trait_methods! {
     clip: "clip";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/clipPathUnits>
-    clipPathUnits: "clipPathUnits";
+    clip_path_units: "clipPathUnits";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/clip-path>
     clip_path: "clip-path";
@@ -1688,10 +1688,10 @@ trait_methods! {
     color_rendering: "color-rendering";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/contentScriptType>
-    contentScriptType: "contentScriptType";
+    content_script_type: "contentScriptType";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/contentStyleType>
-    contentStyleType: "contentStyleType";
+    content_style_type: "contentStyleType";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/crossorigin>
     crossorigin: "crossorigin";
@@ -1715,7 +1715,7 @@ trait_methods! {
     descent: "descent";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/diffuseConstant>
-    diffuseConstant: "diffuseConstant";
+    diffuse_constant: "diffuseConstant";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/direction>
     direction: "direction";
@@ -1739,7 +1739,7 @@ trait_methods! {
     dy: "dy";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/edgeMode>
-    edgeMode: "edgeMode";
+    edge_mode: "edgeMode";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/elevation>
     elevation: "elevation";
@@ -1829,13 +1829,13 @@ trait_methods! {
     glyph_orientation_vertical: "glyph-orientation-vertical";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/glyphRef>
-    glyphRef: "glyphRef";
+    glyph_ref: "glyphRef";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/gradientTransform>
-    gradientTransform: "gradientTransform";
+    gradient_transform: "gradientTransform";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/gradientUnits>
-    gradientUnits: "gradientUnits";
+    gradient_units: "gradientUnits";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/hanging>
     hanging: "hanging";
@@ -1889,28 +1889,28 @@ trait_methods! {
     k4: "k4";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/kernelMatrix>
-    kernelMatrix: "kernelMatrix";
+    kernel_matrix: "kernelMatrix";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/kernelUnitLength>
-    kernelUnitLength: "kernelUnitLength";
+    kernel_unit_length: "kernelUnitLength";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/kerning>
     kerning: "kerning";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/keyPoints>
-    keyPoints: "keyPoints";
+    key_points: "keyPoints";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/keySplines>
-    keySplines: "keySplines";
+    key_splines: "keySplines";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/keyTimes>
-    keyTimes: "keyTimes";
+    key_times: "keyTimes";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/lang>
     lang: "lang";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/lengthAdjust>
-    lengthAdjust: "lengthAdjust";
+    length_adjust: "lengthAdjust";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/letter-spacing>
     letter_spacing: "letter-spacing";
@@ -1919,7 +1919,7 @@ trait_methods! {
     lighting_color: "lighting-color";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/limitingConeAngle>
-    limitingConeAngle: "limitingConeAngle";
+    limiting_cone_angle: "limitingConeAngle";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/local>
     local: "local";
@@ -1930,26 +1930,26 @@ trait_methods! {
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/marker-mid>
     marker_mid: "marker-mid";
 
-    /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/marker_start>
-    marker_start: "marker_start";
+    /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/marker-start>
+    marker_start: "marker-start";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/markerHeight>
-    markerHeight: "markerHeight";
+    marker_height: "markerHeight";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/markerUnits>
-    markerUnits: "markerUnits";
+    marker_units: "markerUnits";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/markerWidth>
-    markerWidth: "markerWidth";
+    marker_width: "markerWidth";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/mask>
     mask: "mask";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/maskContentUnits>
-    maskContentUnits: "maskContentUnits";
+    mask_content_units: "maskContentUnits";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/maskUnits>
-    maskUnits: "maskUnits";
+    mask_units: "maskUnits";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/mathematical>
     mathematical: "mathematical";
@@ -1973,7 +1973,7 @@ trait_methods! {
     name: "name";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/numOctaves>
-    numOctaves: "numOctaves";
+    num_octaves: "numOctaves";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/offset>
     offset: "offset";
@@ -2015,16 +2015,16 @@ trait_methods! {
     path: "path";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/pathLength>
-    pathLength: "pathLength";
+    path_length: "pathLength";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/patternContentUnits>
-    patternContentUnits: "patternContentUnits";
+    pattern_content_units: "patternContentUnits";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/patternTransform>
-    patternTransform: "patternTransform";
+    pattern_transform: "patternTransform";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/patternUnits>
-    patternUnits: "patternUnits";
+    pattern_units: "patternUnits";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/ping>
     ping: "ping";
@@ -2036,22 +2036,22 @@ trait_methods! {
     points: "points";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/pointsAtX>
-    pointsAtX: "pointsAtX";
+    points_at_x: "pointsAtX";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/pointsAtY>
-    pointsAtY: "pointsAtY";
+    points_at_y: "pointsAtY";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/pointsAtZ>
-    pointsAtZ: "pointsAtZ";
+    points_at_z: "pointsAtZ";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAlpha>
-    preserveAlpha: "preserveAlpha";
+    preserve_alpha: "preserveAlpha";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAspectRatio>
-    preserveAspectRatio: "preserveAspectRatio";
+    preserve_aspect_ratio: "preserveAspectRatio";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/primitiveUnits>
-    primitiveUnits: "primitiveUnits";
+    primitive_units: "primitiveUnits";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/r>
     r: "r";
@@ -2060,13 +2060,13 @@ trait_methods! {
     radius: "radius";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/referrerPolicy>
-    referrerPolicy: "referrerPolicy";
+    referrer_policy: "referrerPolicy";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/refX>
-    refX: "refX";
+    ref_x: "refX";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/refY>
-    refY: "refY";
+    ref_y: "refY";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/rel>
     rel: "rel";
@@ -2075,16 +2075,16 @@ trait_methods! {
     rendering_intent: "rendering-intent";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/repeatCount>
-    repeatCount: "repeatCount";
+    repeat_count: "repeatCount";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/repeatDur>
-    repeatDur: "repeatDur";
+    repeat_dur: "repeatDur";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/requiredExtensions>
-    requiredExtensions: "requiredExtensions";
+    required_extensions: "requiredExtensions";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/requiredFeatures>
-    requiredFeatures: "requiredFeatures";
+    required_features: "requiredFeatures";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/restart>
     restart: "restart";
@@ -2120,22 +2120,22 @@ trait_methods! {
     spacing: "spacing";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/specularConstant>
-    specularConstant: "specularConstant";
+    specular_constant: "specularConstant";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/specularExponent>
-    specularExponent: "specularExponent";
+    specular_exponent: "specularExponent";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/speed>
     speed: "speed";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/spreadMethod>
-    spreadMethod: "spreadMethod";
+    spread_method: "spreadMethod";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/startOffset>
-    startOffset: "startOffset";
+    start_offset: "startOffset";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stdDeviation>
-    stdDeviation: "stdDeviation";
+    std_deviation: "stdDeviation";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stemh>
     stemh: "stemh";
@@ -2144,13 +2144,13 @@ trait_methods! {
     stemv: "stemv";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stitchTiles>
-    stitchTiles: "stitchTiles";
+    stitch_tiles: "stitchTiles";
 
-    /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stop_color>
-    stop_color: "stop_color";
+    /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stop-color>
+    stop_color: "stop-color";
 
-    /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stop_opacity>
-    stop_opacity: "stop_opacity";
+    /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stop-opacity>
+    stop_opacity: "stop-opacity";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/strikethrough-position>
     strikethrough_position: "strikethrough-position";
@@ -2189,25 +2189,25 @@ trait_methods! {
     style: "style";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/surfaceScale>
-    surfaceScale: "surfaceScale";
+    surface_scale: "surfaceScale";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/systemLanguage>
-    systemLanguage: "systemLanguage";
+    system_language: "systemLanguage";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/tabindex>
     tabindex: "tabindex";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/tableValues>
-    tableValues: "tableValues";
+    table_values: "tableValues";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/target>
     target: "target";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/targetX>
-    targetX: "targetX";
+    target_x: "targetX";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/targetY>
-    targetY: "targetY";
+    target_y: "targetY";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/text-anchor>
     text_anchor: "text-anchor";
@@ -2219,7 +2219,7 @@ trait_methods! {
     text_rendering: "text-rendering";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/textLength>
-    textLength: "textLength";
+    text_length: "textLength";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/to>
     to: "to";
@@ -2342,6 +2342,6 @@ trait_methods! {
     z: "z";
 
     /// <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/zoomAndPan>
-    zoomAndPan: "zoomAndPan";
+    zoom_and_pan: "zoomAndPan";
 
 }