Repository: typst/typst
File: tests/src/report/html.rs (Rust)

Code before:
                        SliderOpts { min: 0.0, max: 1.0, value: 0.5, step: 0.01 },
                    )
                });
        });
    });
}

fn html_diff(parent: &mut HtmlElem, diff: &FileDiff<diff::Html>) {
    let iframe = |parent: &mut HtmlElem<'_>, data_url: &str| {
        parent
            .iframe()
            .class("html-frame")
            .src(data_url)
            .opt_attr("style", data_url.is_empty().then_some("visibility: hidden"));
    };

    parent.div().class("html-diff").with(|div| {
        let data_url = (diff.left())
            .and_then(|old| old.data())
            .map(|html| html.data_url.as_str())
            .unwrap_or("");
        iframe(div, data_url);

        let data_url = (diff.right())
            .and_then(|res| res.as_ref().ok())
            .map(|html| html.data_url.as_str())
            .unwrap_or("");
        iframe(div, data_url);
    });
}

#[rustfmt::skip]
mod icons {
    #[derive(Copy, Clone, Eq, PartialEq, Hash)]
    pub struct SvgIcon(&'static str);

    impl SvgIcon {
        pub fn as_str(&self) -> &'static str {
            self.0
        }
    }

    pub static RENDER: SvgIcon = SvgIcon("M1 3v10h14V3Zm1.2 1.2h11.6v5.2H9.567a.4.4 0 0 1-.343-.195L7.45 6.254a1.58 1.58 0 0 0-1.431-.756c-.553.021-1.096.313-1.372.863L2.2 11.26Zm9.3.8A1.5 1.5 0 0 0 10 6.5 1.5 1.5 0 0 0 11.5 8 1.5 1.5 0 0 0 13 6.5 1.5 1.5 0 0 0 11.5 5M6.064 6.656c.133-.005.268.066.358.215l1.771 2.951c.29.481.812.778 1.373.778h4.235v1.2H3.27l2.452-4.902c.077-.155.208-.237.341-.242");
    pub static PDF: SvgIcon = SvgIcon("M7.56 3.608 8 4.492l.442-.884c.05-.173.059-.373.011-.495a.2.2 0 0 0-.084-.106c-.045-.028-.15-.073-.369-.073-.218 0-.323.045-.369.073a.2.2 0 0 0-.084.106c-.047.122-.04.322.011.495m-.562-1.62c.28-.175.621-.254 1.003-.254s.722.08 1.003.254c.286.179.468.429.57.692.19.493.103 1.024-.004 1.343l-.013.04-.02.039-.855 1.711 2.68 4.644 1.905.115.043.002.042.009c.33.067.833.257 1.165.669.177.22.303.501.314.838.011.331-.09.666-.28.996-.192.331-.431.586-.723.742-.298.159-.605.19-.883.147-.523-.082-.94-.423-1.162-.674l-.029-.032-.023-.036-1.056-1.6H5.323L4.27 13.23l-.023.035-.028.032c-.224.252-.64.593-1.163.675a1.4 1.4 0 0 1-.883-.147c-.292-.156-.531-.411-.722-.742-.191-.33-.292-.665-.281-.996.011-.337.138-.62.314-.838.332-.412.836-.602 1.165-.67l.042-.008.043-.003 1.91-.114 2.677-4.64-.856-1.712-.019-.038-.013-.04c-.107-.32-.194-.85-.003-1.344.102-.263.283-.513.569-.692m5.163 9.72.987.059c.175.042.352.135.434.238a.2.2 0 0 1 .05.126c.002.053-.012.167-.121.355-.11.19-.201.258-.248.283a.2.2 0 0 1-.133.02c-.13-.02-.3-.127-.424-.257zm-8.322-.004-.545.825c-.124.13-.293.236-.423.257a.2.2 0 0 1-.134-.02c-.047-.025-.139-.094-.248-.283s-.122-.303-.12-.356a.2.2 0 0 1 .049-.126c.082-.102.26-.195.434-.238zm6.118-1.27L8 7.039l-1.965 3.395z");
    pub static PDFTAGS: SvgIcon = SvgIcon("m2.732.732.084.747.051.458 1.227.168-.002-.013 3.287.365a3.4 3.4 0 0 1 2.03.975l4.01 4.011-.32.32.85.848.744-.744.424-.424-.424-.423-4.435-4.436a4.6 4.6 0 0 0-2.746-1.32L3.479.816Zm-2 2 .084.747.448 4.033a4.6 4.6 0 0 0 1.32 2.746l4.436 4.435.423.424.424-.424 4.826-4.826.424-.424-.424-.423-4.435-4.436a4.6 4.6 0 0 0-2.746-1.32l-4.033-.448Zm1.36 1.36 3.287.365a3.4 3.4 0 0 1 2.03.975l4.01 4.011-3.976 3.977-4.011-4.012a3.4 3.4 0 0 1-.975-2.03ZM5 6a1 1 0 1 0 0 2 1 1 0 0 0 0-2");
    pub static SVG: SvgIcon = SvgIcon("M2.93 12v2h2v-2zm0-10v2h2V2Zm.46 2v8h1.2V4Zm9.68 0c-1.46 0-3.741-.01-5.726.438-.993.223-1.922.557-2.647 1.12l-.107.088v4.708q.052.046.107.087c.725.564 1.654.898 2.647 1.121 1.985.447 4.266.438 5.726.438v-1.2c-1.461 0-3.678-.006-5.463-.407-.892-.201-1.666-.506-2.171-.899-.506-.393-.764-.82-.764-1.494 0-.673.258-1.101.764-1.494.505-.393 1.28-.698 2.171-.899C9.392 5.206 11.61 5.2 13.07 5.2Z");
    pub static HTML: SvgIcon = SvgIcon("M8 1.4A6.61 6.61 0 0 0 1.4 8c0 3.638 2.962 6.6 6.6 6.6s6.6-2.962 6.6-6.6S11.638 1.4 8 1.4m1.824.883c-.106.149-.2.31-.285.47-.166.316-.281.63-.281.84 0 .287.21.594.37.772a.3.3 0 0 0 .224.094.33.33 0 0 0 .332-.332v-.1c0-.182.086-.373.189-.533a.35.35 0 0 1 .37-.15q.137.08.27.17l.003.002a.46.46 0 0 1 .093.279v.121c0 .323-.21.609-.52.705l-.868.272-.496.23c-.286.133-.565.302-.729.57-.093.152-.166.328-.166.496 0 .433.465.866.928.866.2 0 .409-.17.584-.371.253-.291.548-.56.916-.674.504-.157 1.145-.052 1.262.463q.016.075.017.148c0 .216-.117.217-.232.217-.116 0-.23 0-.23.217 0 .456.668.285 1.04.021.193-.137.348-.282.348-.455 0-.12.105-.199.209-.187a5.4 5.4 0 0 1 .201 2.119 2.7 2.7 0 0 0-1.146-.475c-.563-.089-1.133-.158-1.53-.158-.26 0-.553-.03-.845-.059a8 8 0 0 0-.942-.054c-.472.014-.816.142-.816.572 0 .325-.085.695-.166 1.043-.148.634-.279 1.193.166 1.252 1.216.161 1.96 1.033 2.31 2.164-.723.36-1.54.562-2.404.562a5.4 5.4 0 0 1-2.084-.414l-.014.035q.029-.079.05-.162c.04-.171.075-.3.1-.367.065-.164.208-.297.376-.453.237-.22.524-.486.705-.95.15-.383-.487-.76-1.229-1.048a2.1 2.1 0 0 0-.818-.146c-.598.015-1.157.297-1.47.843q-.07.121-.128.235a5.4 5.4 0 0 1-.767-1.825l.736.49A.35.35 0 0 0 4 9.349c0-.193.159-.341.34-.276.194.07.432.2.66.428q.121.119.244.17c.417.18.495-.431.174-.752a.77.77 0 0 1-.133-.938c.203-.34.466-.73.715-.98.32-.32-.195-1.092-.67-1.643a2.4 2.4 0 0 0-.766-.574l-.222-.113a3 3 0 0 0-.45-.182A5.4 5.4 0 0 1 5 3.506C5.005 4.29 5.15 5 5.627 5c.206 0 .395-.023.564-.059.636-.134.84-.827.682-1.457l-.125-.494a1 1 0 0 0-.088-.224A5.4 5.4 0 0 1 8 2.6c.522 0 1.027.073 1.504.21.01-.019.025-.037.035-.056.085-.161.178-.322.285-.47M8.415 3.967a.25.25 0 0 0-.233.32l.138.47a.418.418 0 1 0 .645-.456l-.4-.285a.25.25 0 0 0-.15-.05m2.503 2.756a.4.4 0 0 0-.145.039c-.36.18-.233.724.17.724a.383.383 0 1 0-.025-.764m-5.102 6.502-.035.066z");

    pub static VISUAL: SvgIcon = SvgIcon("m13.152 3.152-1.586 1.586C10.606 4.242 9.416 3.9 8 3.9c-1.93 0-3.44.634-4.52 1.43-1.078.797-1.73 1.73-2.03 2.434l-.12.275.149.258c.384.673 1.127 1.593 2.222 2.379C4.797 11.46 6.254 12.1 8 12.1s3.203-.639 4.299-1.424c1.095-.786 1.838-1.706 2.222-2.38l.149-.257-.12-.275c-.292-.685-.917-1.587-1.945-2.37L14 4ZM8 5.1c1.67 0 2.91.533 3.807 1.195.774.572 1.164 1.202 1.418 1.678-.33.498-.814 1.144-1.625 1.726-.938.673-2.146 1.201-3.6 1.201s-2.662-.528-3.6-1.2c-.81-.583-1.294-1.23-1.625-1.727.254-.476.644-1.106 1.418-1.678C5.09 5.633 6.33 5.1 8 5.1M8 6a2 2 0 0 0-2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0-2-2");
    pub static TEXT: SvgIcon = SvgIcon("M11.291 5.555a2 2 0 0 0-1.117.316q-.493.314-.776.904-.279.591-.279 1.418 0 .826.283 1.393.287.564.776.853.493.288 1.107.288.475 0 .772-.149a1.4 1.4 0 0 0 .466-.351 2.3 2.3 0 0 0 .262-.368h.065v1.02q0 .607-.373.883-.375.28-.95.281-.418 0-.683-.12a1.3 1.3 0 0 1-.42-.286 2 2 0 0 1-.242-.313l-.868.358q.14.316.418.582.28.266.723.43.445.16 1.063.161.66 0 1.187-.207.53-.205.84-.632.31-.43.31-1.098V5.621h-.988v.842h-.074a3 3 0 0 0-.26-.375 1.4 1.4 0 0 0-.463-.371q-.297-.162-.779-.162m.217.857q.441 0 .742.225.3.222.455.62.155.4.154.923 0 .535-.158.92-.154.381-.459.588-.3.2-.734.2-.45.001-.756-.214a1.33 1.33 0 0 1-.459-.602 2.4 2.4 0 0 1-.154-.892q0-.496.15-.899a1.4 1.4 0 0 1 .459-.633q.304-.236.76-.236M4.39 3.895l-2.487 6.91h1.108l.633-1.83h2.697l.633 1.83h1.107l-2.486-6.91Zm.578 1.255h.052L6.04 8.098H3.95Z");


Review comment (suggestion):
it would be good to add the [`sandbox` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/iframe#sandbox) (with no / empty value) to ensure the contained HTML is maximally restricted in what it is allowed to do.

Code after:
                        icons::ALIGN_RIGHT,
                        false,
                    );
                },
            );

            div.fieldset()
                .class("control-group image-blend-control")
                .with(|fieldset| {
                    slider(
                        fieldset,
                        "image-blend",
                        "Blend",
                        Some(icons::VIEW_BLEND),
                        SliderOpts { min: 0.0, max: 1.0, value: 0.5, step: 0.01 },
                    )
                });
        });
    });
}

fn html_diff(parent: &mut HtmlElem, diff: &FileDiff<diff::Html>) {
    let iframe = |parent: &mut HtmlElem<'_>, data_url: &str| {
        parent
            .iframe()
            .class("html-frame")
            .src(data_url)
            .sandbox(true) // Apply all restrictions to the sandbox.
            .opt_attr("style", data_url.is_empty().then_some("visibility: hidden"));
    };

    parent.div().class("html-diff").with(|div| {
        let data_url = (diff.left())
            .and_then(|old| old.data())
            .map(|html| html.data_url.as_str())
            .unwrap_or("");
        iframe(div, data_url);

        let data_url = (diff.right())
            .and_then(|res| res.as_ref().ok())
            .map(|html| html.data_url.as_str())
            .unwrap_or("");
        iframe(div, data_url);
    });
}

#[rustfmt::skip]
mod icons {
    #[derive(Copy, Clone, Eq, PartialEq, Hash)]
    pub struct SvgIcon(&'static str);