use crate::plugins::remove_unknowns_and_defaults::RemoveUnknownsAndDefaultsConfig;
use std::collections::HashMap;
use std::collections::HashSet;
use vexy_vsvg::ast::Element;
pub(crate) fn known_attributes() -> &'static HashSet<&'static str> {
static KNOWN_ATTRIBUTES: std::sync::OnceLock<HashSet<&'static str>> =
std::sync::OnceLock::new();
KNOWN_ATTRIBUTES.get_or_init(|| {
[
"id",
"class",
"style",
"transform",
"x",
"y",
"width",
"height",
"fill",
"stroke",
"stroke-width",
"stroke-linecap",
"stroke-linejoin",
"stroke-miterlimit",
"stroke-dasharray",
"stroke-dashoffset",
"stroke-opacity",
"fill-opacity",
"opacity",
"visibility",
"display",
"overflow",
"clip-path",
"clip-rule",
"mask",
"filter",
"marker-start",
"marker-mid",
"marker-end",
"color",
"color-interpolation",
"color-interpolation-filters",
"color-profile",
"color-rendering",
"cursor",
"direction",
"dominant-baseline",
"enable-background",
"fill-rule",
"flood-color",
"flood-opacity",
"font-family",
"font-size",
"font-size-adjust",
"font-stretch",
"font-style",
"font-variant",
"font-weight",
"glyph-orientation-horizontal",
"glyph-orientation-vertical",
"image-rendering",
"isolation",
"kerning",
"letter-spacing",
"lighting-color",
"marker",
"mix-blend-mode",
"paint-order",
"pointer-events",
"shape-rendering",
"stop-color",
"stop-opacity",
"text-anchor",
"text-decoration",
"text-rendering",
"transform-origin",
"unicode-bidi",
"vector-effect",
"white-space",
"word-spacing",
"writing-mode",
"cx",
"cy",
"r",
"rx",
"ry",
"x1",
"y1",
"x2",
"y2",
"dx",
"dy",
"rotate",
"textLength",
"lengthAdjust",
"startOffset",
"method",
"spacing",
"refX",
"refY",
"markerUnits",
"markerWidth",
"markerHeight",
"orient",
"preserveAspectRatio",
"viewBox",
"points",
"pathLength",
"d",
"href",
"xlink:href",
"type",
"media",
"title",
"xml:space",
"xml:lang",
"xml:base",
"xmlns",
"xmlns:xlink",
"version",
"baseProfile",
"contentScriptType",
"contentStyleType",
"zoomAndPan",
"attributeName",
"attributeType",
"begin",
"dur",
"end",
"min",
"max",
"restart",
"repeatCount",
"repeatDur",
"fill",
"calcMode",
"values",
"keyTimes",
"keySplines",
"from",
"to",
"by",
"additive",
"accumulate",
"in",
"in2",
"result",
"mode",
"operator",
"k1",
"k2",
"k3",
"k4",
"scale",
"xChannelSelector",
"yChannelSelector",
"stdDeviation",
"edgeMode",
"kernelMatrix",
"divisor",
"bias",
"targetX",
"targetY",
"surfaceScale",
"specularConstant",
"specularExponent",
"limitingConeAngle",
"gradientUnits",
"gradientTransform",
"spreadMethod",
"fx",
"fy",
"fr",
"offset",
"patternUnits",
"patternContentUnits",
"patternTransform",
"maskUnits",
"maskContentUnits",
"clipPathUnits",
"alignment-baseline",
"baseline-shift",
"text-overflow",
"line-height",
"requiredExtensions",
"requiredFeatures",
"systemLanguage",
]
.into_iter()
.collect()
})
}
pub(crate) fn default_attribute_values() -> &'static HashMap<&'static str, &'static str> {
static DEFAULT_VALUES: std::sync::OnceLock<HashMap<&'static str, &'static str>> =
std::sync::OnceLock::new();
DEFAULT_VALUES.get_or_init(|| {
[
("x", "0"),
("y", "0"),
("width", "0"),
("height", "0"),
("fill", "black"),
("stroke", "none"),
("stroke-width", "1"),
("stroke-linecap", "butt"),
("stroke-linejoin", "miter"),
("stroke-miterlimit", "4"),
("stroke-dasharray", "none"),
("stroke-dashoffset", "0"),
("stroke-opacity", "1"),
("fill-opacity", "1"),
("opacity", "1"),
("visibility", "visible"),
("display", "inline"),
("overflow", "visible"),
("clip-rule", "nonzero"),
("fill-rule", "nonzero"),
("color-interpolation", "sRGB"),
("color-interpolation-filters", "linearRGB"),
("color-rendering", "auto"),
("dominant-baseline", "auto"),
("enable-background", "accumulate"),
("font-size", "medium"),
("font-stretch", "normal"),
("font-style", "normal"),
("font-variant", "normal"),
("font-weight", "normal"),
("glyph-orientation-horizontal", "0deg"),
("glyph-orientation-vertical", "auto"),
("image-rendering", "auto"),
("kerning", "auto"),
("letter-spacing", "normal"),
("lighting-color", "normal"),
("marker", "none"),
("marker-start", "none"),
("marker-mid", "none"),
("marker-end", "none"),
("pointer-events", "visiblePainted"),
("shape-rendering", "auto"),
("stop-color", "black"),
("stop-opacity", "1"),
("text-anchor", "start"),
("text-decoration", "none"),
("text-rendering", "auto"),
("unicode-bidi", "normal"),
("vector-effect", "none"),
("word-spacing", "normal"),
("writing-mode", "lr-tb"),
("direction", "ltr"),
("color", "black"),
("cx", "0"),
("cy", "0"),
("r", "0"),
("rx", "0"),
("ry", "0"),
("x1", "0"),
("y1", "0"),
("x2", "0"),
("y2", "0"),
("dx", "0"),
("dy", "0"),
("rotate", "0"),
("textLength", "0"),
("lengthAdjust", "spacing"),
("startOffset", "0"),
("refX", "0"),
("refY", "0"),
("markerUnits", "strokeWidth"),
("markerWidth", "3"),
("markerHeight", "3"),
("orient", "0"),
("patternUnits", "objectBoundingBox"),
("patternContentUnits", "userSpaceOnUse"),
("maskUnits", "objectBoundingBox"),
("maskContentUnits", "userSpaceOnUse"),
("clipPathUnits", "userSpaceOnUse"),
("gradientUnits", "objectBoundingBox"),
("spreadMethod", "pad"),
("fx", "cx"),
("fy", "cy"),
("filterUnits", "objectBoundingBox"),
("primitiveUnits", "userSpaceOnUse"),
("begin", "0s"),
("dur", "indefinite"),
("repeatCount", "0"),
("repeatDur", "indefinite"),
("restart", "always"),
("calcMode", "linear"),
("additive", "replace"),
("accumulate", "none"),
("keyTimes", "0;1"),
("keySplines", "0 0 1 1"),
("edgeMode", "duplicate"),
("operator", "over"),
("k1", "0"),
("k2", "0"),
("k3", "0"),
("k4", "0"),
("divisor", "1"),
("bias", "0"),
("targetX", "1"),
("targetY", "1"),
("surfaceScale", "1"),
("specularConstant", "1"),
("specularExponent", "1"),
("method", "align"),
("spacing", "exact"),
("transform-origin", "0 0"),
("version", "1.1"),
("baseProfile", "none"),
("preserveAspectRatio", "xMidYMid meet"),
("zoomAndPan", "magnify"),
("contentScriptType", "application/ecmascript"),
("contentStyleType", "text/css"),
("type", "text/css"),
("media", "all"),
("target", "_self"),
("xlink:type", "simple"),
("xlink:show", "other"),
("xlink:actuate", "onRequest"),
("xml:space", "default"),
("requiredFeatures", ""),
("requiredExtensions", ""),
("systemLanguage", ""),
("externalResourcesRequired", "false"),
("class", ""),
("style", ""),
("transform", ""),
("tabindex", "0"),
("lang", ""),
("xml:lang", ""),
("role", ""),
("aria-label", ""),
("aria-labelledby", ""),
("aria-describedby", ""),
("aria-details", ""),
("title", ""),
("desc", ""),
("alignment-baseline", "auto"),
("baseline-shift", "0"),
("clip", "auto"),
("clip-path", "none"),
("color-profile", "auto"),
("cursor", "auto"),
("filter", "none"),
("flood-color", "black"),
("flood-opacity", "1"),
("font-family", ""),
("font-size-adjust", "none"),
("glyph-orientation-horizontal", "0"),
("glyph-orientation-vertical", "auto"),
("image-rendering", "auto"),
("mask", "none"),
("text-overflow", "clip"),
("white-space", "normal"),
("line-height", "normal"),
("paint-order", "normal"),
("isolation", "auto"),
("mix-blend-mode", "normal"),
("solid-color", "black"),
("solid-opacity", "1"),
("vector-effect", "none"),
("stop-color", "black"),
("stop-opacity", "1"),
("color-interpolation", "sRGB"),
("color-interpolation-filters", "linearRGB"),
("color-rendering", "auto"),
("fill", "black"),
("fill-opacity", "1"),
("fill-rule", "nonzero"),
("image-rendering", "auto"),
("marker", "none"),
("marker-end", "none"),
("marker-mid", "none"),
("marker-start", "none"),
("shape-rendering", "auto"),
("stroke", "none"),
("stroke-dasharray", "none"),
("stroke-dashoffset", "0"),
("stroke-linecap", "butt"),
("stroke-linejoin", "miter"),
("stroke-miterlimit", "4"),
("stroke-opacity", "1"),
("stroke-width", "1"),
("text-rendering", "auto"),
("alignment-baseline", "auto"),
("baseline-shift", "baseline"),
("dominant-baseline", "auto"),
("glyph-orientation-horizontal", "0deg"),
("glyph-orientation-vertical", "auto"),
("kerning", "auto"),
("text-anchor", "start"),
("writing-mode", "lr-tb"),
("font-stretch", "normal"),
("font-style", "normal"),
("font-variant", "normal"),
("font-weight", "normal"),
("direction", "ltr"),
("letter-spacing", "normal"),
("text-decoration", "none"),
("unicode-bidi", "normal"),
("word-spacing", "normal"),
("clip-rule", "nonzero"),
("mask-type", "luminance"),
("display", "inline"),
("overflow", "visible"),
("visibility", "visible"),
("color-profile", "sRGB"),
("opacity", "1"),
("lighting-color", "white"),
("enable-background", "accumulate"),
("xml:base", ""),
("requiredFeatures", ""),
("requiredExtensions", ""),
("systemLanguage", ""),
("id", ""),
("tabindex", "0"),
("focusable", "auto"),
("aria-hidden", "false"),
("role", ""),
("aria-label", ""),
("aria-labelledby", ""),
("aria-describedby", ""),
("aria-details", ""),
("aria-haspopup", "false"),
("aria-controls", ""),
("aria-flowto", ""),
("aria-owns", ""),
("aria-activedescendant", ""),
("aria-live", "off"),
("aria-atomic", "false"),
("aria-relevant", "additions text"),
("aria-busy", "false"),
("aria-disabled", "false"),
("aria-grabbed", "undefined"),
("aria-dropeffect", "none"),
("aria-expanded", "undefined"),
("aria-pressed", "undefined"),
("aria-checked", "undefined"),
("aria-selected", "undefined"),
("aria-required", "false"),
("aria-readonly", "false"),
("aria-multiline", "false"),
("aria-multiselectable", "false"),
("aria-orientation", "undefined"),
("aria-autocomplete", "none"),
("aria-invalid", "false"),
("aria-hidden", "false"),
("aria-level", ""),
("aria-valuemin", ""),
("aria-valuemax", ""),
("aria-valuenow", ""),
("aria-valuetext", ""),
("aria-setsize", ""),
("aria-posinset", ""),
("aria-colspan", ""),
("aria-rowspan", ""),
("aria-rowindex", ""),
("aria-colindex", ""),
("aria-sort", "none"),
("aria-modal", "false"),
("aria-current", "false"),
("aria-placeholder", ""),
("aria-roledescription", ""),
("aria-keyshortcuts", ""),
("color-scheme", "normal"),
("rotate", "0"),
("scale", "1"),
("method", "align"),
("spacing", "exact"),
("startOffset", "0"),
("lengthAdjust", "spacing"),
("alignment-baseline", "auto"),
("baseline-shift", "baseline"),
("preserveAspectRatio", "xMidYMid meet"),
("zoomAndPan", "magnify"),
("contentScriptType", "application/ecmascript"),
("contentStyleType", "text/css"),
("type", "text/css"),
("media", "all"),
("target", "_self"),
]
.into_iter()
.collect()
})
}
pub(crate) fn is_inheritable_presentation_attr_pub(name: &str) -> bool {
is_inheritable_presentation_attr(name)
}
fn is_inheritable_presentation_attr(name: &str) -> bool {
matches!(
name,
"clip-rule"
| "color"
| "color-interpolation"
| "color-interpolation-filters"
| "cursor"
| "direction"
| "dominant-baseline"
| "fill"
| "fill-opacity"
| "fill-rule"
| "font"
| "font-family"
| "font-size"
| "font-size-adjust"
| "font-stretch"
| "font-style"
| "font-variant"
| "font-weight"
| "glyph-orientation-horizontal"
| "glyph-orientation-vertical"
| "image-rendering"
| "letter-spacing"
| "marker"
| "marker-end"
| "marker-mid"
| "marker-start"
| "opacity"
| "overflow"
| "paint-order"
| "pointer-events"
| "shape-rendering"
| "stroke"
| "stroke-dasharray"
| "stroke-dashoffset"
| "stroke-linecap"
| "stroke-linejoin"
| "stroke-miterlimit"
| "stroke-opacity"
| "stroke-width"
| "text-anchor"
| "text-decoration"
| "text-rendering"
| "visibility"
| "word-spacing"
| "writing-mode"
)
}
pub(crate) fn should_remove_attribute(
attr_name: &str,
attr_value: &str,
element: &Element,
inherited_value: Option<&str>,
config: &RemoveUnknownsAndDefaultsConfig,
) -> bool {
if config.keep_data_attrs && attr_name.starts_with("data-") {
return false;
}
if config.keep_aria_attrs && attr_name.starts_with("aria-") {
return false;
}
if config.keep_role_attr && attr_name == "role" {
return false;
}
if attr_name.starts_with("xml:")
|| attr_name.starts_with("xlink:")
|| attr_name.starts_with("xmlns")
{
return false;
}
if config.unknown_attrs && !known_attributes().contains(attr_name) {
return true;
}
if config.default_attrs {
if let Some(default_value) = default_attribute_values().get(attr_name) {
if element.attr("id").is_some() {
return false;
}
if attr_value == *default_value {
if is_inheritable_presentation_attr(attr_name) && !element.children.is_empty() {
return false;
}
if is_inheritable_presentation_attr(attr_name) {
if let Some(parent_val) = inherited_value {
if parent_val != *default_value {
return false;
}
}
}
return true;
}
}
}
false
}