# Mask and Gradient Maintenance Smoke
Run this manual smoke from the repository root after changing gradient
validation, gradient import/export, native background promotion, icon
expansion, or mask rejection. It keeps XML in memory except for temporary SVG
fixtures; do not turn it into a test framework or example deck.
```bash
python3 - <<'PY'
import math
import re
import sys
import tempfile
from pathlib import Path
from xml.etree import ElementTree as ET
scripts = Path("skills/ppt-master/scripts").resolve()
sys.path.insert(0, str(scripts))
from pptx_to_svg.color_resolver import ColorPalette
from pptx_to_svg.fill_to_svg import _angle_to_unit_endpoints, resolve_fill
from svg_quality_checker import SVGQualityChecker
from svg_to_pptx.drawingml.converter import (
SvgNativeConversionError,
convert_svg_to_slide_shapes,
)
from svg_to_pptx.drawingml.styles import build_gradient_fill
from svg_to_pptx.drawingml.utils import (
parse_project_linear_gradient_coordinate,
project_gradient_errors,
project_mask_errors,
)
SVG_NS = "http://www.w3.org/2000/svg"
def svg(fragment):
return ET.fromstring(
f''
)
valid = svg(
"""
"""
)
assert not project_gradient_errors(valid)
linear, radial = list(valid.find(f"{{{SVG_NS}}}defs"))
linear_xml = build_gradient_fill(linear)
radial_xml = build_gradient_fill(radial)
assert '' in linear_xml
assert '' in linear_xml
assert '' in radial_xml
assert (
''
in radial_xml
)
radial.set("fx", "0.8")
radial.set("fy", "0.2")
focused_xml = build_gradient_fill(radial)
assert (
''
in focused_xml
)
native_gradient = ET.fromstring(
f''
f'{focused_xml}'
)[0]
restored = resolve_fill(native_gradient, None)
assert 'cx="0.5" cy="0.5" r="0.5" fx="0.8" fy="0.2"' in restored.defs[0]
assert '' in (
build_gradient_fill(ET.fromstring(restored.defs[0]))
)
radial.set("fx", "0")
radial.set("fy", "0")
outside_focus_errors = project_gradient_errors(valid)
assert any(
"must lie within the canonical circle" in error
for error in outside_focus_errors
), outside_focus_errors
try:
build_gradient_fill(radial)
except ValueError as exc:
assert "must lie within the canonical circle" in str(exc)
else:
raise AssertionError("outside radial focus reached DrawingML")
radial.set("fx", "0.8")
radial.set("fy", "0.2")
diagnostics = []
palette = ColorPalette(
None,
None,
strict=False,
diagnostic_sink=lambda code, message, fallback: diagnostics.append(
(code, message, fallback)
),
)
outside_native_xml = focused_xml.replace(
'l="80000" t="20000" r="20000" b="80000"',
'l="0" t="0" r="100000" b="100000"',
)
outside_native_gradient = ET.fromstring(
f''
f"{outside_native_xml}"
)[0]
normalized = resolve_fill(outside_native_gradient, palette)
assert " fx=" not in normalized.defs[0]
assert " fy=" not in normalized.defs[0]
assert any(
code == "path-gradient-focus-normalized"
for code, _message, _fallback in diagnostics
)
with tempfile.TemporaryDirectory(prefix="ppt-master-gradient-smoke-") as tmp:
source = Path(tmp) / "gradient.svg"
source.write_text(
ET.tostring(valid, encoding="unicode"),
encoding="utf-8",
)
trace = []
slide_xml, *_ = convert_svg_to_slide_shapes(source, trace_out=trace)
assert slide_xml.count("") == 1
assert "" in slide_xml
assert trace[0]["summary"]["promoted_backgrounds"] == 1
assert any(
event.get("decision") == "native-background"
for event in trace[0]["events"]
)
invalid_gradients = [
(
"""
""",
"requires at least two direct children",
),
(
"""
""",
"offsets must be non-decreasing",
),
(
"""
""",
"linear gradient axis must not collapse to one point",
),
]
for definition, expected in invalid_gradients:
errors = project_gradient_errors(svg(f"{definition}"))
assert any(expected in error for error in errors), errors
mask_cases = [
"""""",
"""""",
"""""",
]
for fragment in mask_cases:
errors = project_mask_errors(svg(fragment))
assert any("unsupported SVG mask" in error for error in errors), errors
checker = SVGQualityChecker()
with tempfile.TemporaryDirectory(prefix="ppt-master-mask-smoke-") as tmp:
for index, fragment in enumerate(mask_cases, start=1):
source = Path(tmp) / f"mask-{index}.svg"
source.write_text(
ET.tostring(svg(fragment), encoding="unicode"),
encoding="utf-8",
)
checked = checker.check_file(str(source))
assert any("mask" in error.lower() for error in checked["errors"])
try:
convert_svg_to_slide_shapes(source)
except SvgNativeConversionError as exc:
assert "invalid project mask" in str(exc)
else:
raise AssertionError(f"native export accepted {source.name}")
with tempfile.TemporaryDirectory(prefix="ppt-master-icon-mask-smoke-") as tmp:
project = Path(tmp)
icon_dir = project / "icons" / "imported"
icon_dir.mkdir(parents=True)
(icon_dir / "masked.svg").write_text(
f"""""",
encoding="utf-8",
)
source = project / "icon-mask.svg"
source.write_text(
ET.tostring(
svg(
""""""
),
encoding="unicode",
),
encoding="utf-8",
)
checked = checker.check_file(str(source))
assert any(
"Icon imported/masked" in error and "mask" in error.lower()
for error in checked["errors"]
)
try:
convert_svg_to_slide_shapes(source)
except SvgNativeConversionError as exc:
assert "invalid project mask" in str(exc)
else:
raise AssertionError("native export accepted a masked icon")
x1, y1, x2, y2 = _angle_to_unit_endpoints(30)
assert any(value < 0 or value > 1 for value in (x1, y1, x2, y2))
for value in (x1, y1, x2, y2):
assert math.isclose(
parse_project_linear_gradient_coordinate(str(value)),
value,
abs_tol=1e-9,
)
roundtrip = svg(
f"""
"""
)
assert not project_gradient_errors(roundtrip)
roundtrip_gradient = roundtrip.find(
f"{{{SVG_NS}}}defs/{{{SVG_NS}}}linearGradient"
)
angle = int(
re.search(
r'