Push 3 (slur quality) 1/3: render dashed/dotted slurs faithfully
E2 drew every slur solid and surfaced a SlurLineStyleNotRendered diagnostic for a non-Solid authored line. That deferral is now lifted: the Curve primitive gains a `line: LineStyle` (from the slur's SpanStyle.line), threaded through the resolved canonical encode (a per-curve style byte), the engrave remap, and casting; render-svg emits stroke-dasharray (dashed = "0.5 0.35"; dotted = round-capped "0 0.28"). The diagnostic variant is removed — the style is rendered, not deferred, so `req:layoutir:slur-curve`'s "never silently rendered solid" is satisfied by faithful rendering rather than a surfaced gap. ENGRAVER_VERSION 5→6 (a dashed/dotted slur's resolved bytes and SVG differ). Zero churn beyond the one dashed slur: the slur fixture's two solid curves are byte-identical; only the editorial slur's <path> gained the dasharray. Solid slurs and slur-free scores are unchanged. 932 tests, conformance 8/8. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
693150e43e
commit
c5173d275e
|
|
@ -132,8 +132,11 @@ pub struct Engraver {
|
|||
/// unchanged), and to `5` when slur curves landed (a slur-bearing score gains
|
||||
/// a drawn cubic-bézier curve where version `4` had only a traced anchor; the
|
||||
/// resolved output now carries a third primitive kind, so its canonical bytes
|
||||
/// differ; slur-free scores draw the same ink as before).
|
||||
pub const ENGRAVER_VERSION: SolverVersion = SolverVersion(5);
|
||||
/// differ; slur-free scores draw the same ink as before), and to `6` when slur
|
||||
/// curves gained a line pattern (a dashed or dotted slur renders its authored
|
||||
/// `SpanStyle.line` faithfully; a curve's canonical bytes now include its line
|
||||
/// style; solid slurs and slur-free scores are unchanged).
|
||||
pub const ENGRAVER_VERSION: SolverVersion = SolverVersion(6);
|
||||
|
||||
impl Engraver {
|
||||
/// An engraver casting off against the given page geometry.
|
||||
|
|
@ -500,6 +503,7 @@ impl HorizontalRemap {
|
|||
thickness: c.thickness,
|
||||
layer: c.layer,
|
||||
style: c.style,
|
||||
line: c.line,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
|
|
|
|||
|
|
@ -112,6 +112,9 @@ pub struct Curve {
|
|||
pub thickness: StaffSpace,
|
||||
pub layer: i32,
|
||||
pub style: GlyphStyle,
|
||||
/// The line pattern the renderer strokes the path with (a slur's authored
|
||||
/// `SpanStyle.line`). Solid, dashed, or dotted.
|
||||
pub line: LineStyle,
|
||||
}
|
||||
|
||||
impl Curve {
|
||||
|
|
@ -176,11 +179,6 @@ pub enum LayoutDiagnosticKind {
|
|||
/// sixteenth-or-shorter rest); the object is carried as a traced anchor
|
||||
/// rather than drawn at a guessed shape.
|
||||
UnbundledGlyph(GlyphReference),
|
||||
/// A slur carries an authored non-`Solid` line style (dashed/dotted) that
|
||||
/// the Minimal tier does not render — the curve is drawn solid, and the
|
||||
/// unrendered style is surfaced here rather than silently dropped (its dash
|
||||
/// pattern is a higher-tier refinement).
|
||||
SlurLineStyleNotRendered,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
|
||||
|
|
@ -1476,20 +1474,7 @@ pub fn try_to_constrained(
|
|||
_ => None,
|
||||
};
|
||||
match curve {
|
||||
Some(curve) => {
|
||||
// A drawn slur whose authored line style is not solid
|
||||
// renders solid at this tier; surface the gap so the
|
||||
// dash/dotted intent is not silently lost.
|
||||
if let Some(LayoutContent::Slur(slur)) = content {
|
||||
if slur.line != LineStyle::Solid {
|
||||
emit.diag(
|
||||
provenance.source,
|
||||
LayoutDiagnosticKind::SlurLineStyleNotRendered,
|
||||
);
|
||||
}
|
||||
}
|
||||
emit.curve(curve);
|
||||
}
|
||||
Some(curve) => emit.curve(curve),
|
||||
None => emit.stroke(anchor(provenance, Point::new(default_x, yo))),
|
||||
}
|
||||
}
|
||||
|
|
@ -2222,6 +2207,9 @@ fn slur_curve(
|
|||
thickness: StaffSpace(thickness),
|
||||
layer: 0,
|
||||
style: ink(),
|
||||
// The authored line pattern is rendered faithfully (dashed/dotted),
|
||||
// not deferred — the renderer strokes the path with it.
|
||||
line: slur.line,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -4436,12 +4424,17 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn an_authored_dashed_slur_draws_solid_but_surfaces_a_diagnostic() {
|
||||
fn an_authored_dashed_slur_renders_a_dashed_curve() {
|
||||
use epiphany_core::{LineStyle, SpanStyle};
|
||||
let (mut score, _) = repeat_ready_score(45);
|
||||
let events = region_a_events(&score);
|
||||
let id: SlurId = score.identity.mint();
|
||||
let mut dashed = slur(id, events[0], events[2], None);
|
||||
let solid_id: SlurId = score.identity.mint();
|
||||
let dashed_id: SlurId = score.identity.mint();
|
||||
score
|
||||
.cross_cutting
|
||||
.slurs
|
||||
.push(slur(solid_id, events[0], events[2], None));
|
||||
let mut dashed = slur(dashed_id, events[0], events[2], None);
|
||||
dashed.style = SpanStyle {
|
||||
line: LineStyle::Dashed,
|
||||
thickness: None,
|
||||
|
|
@ -4449,16 +4442,25 @@ mod tests {
|
|||
score.cross_cutting.slurs.push(dashed);
|
||||
let constrained = to_constrained(&to_logical(&score));
|
||||
|
||||
// The curve still draws (solid) — ink and provenance preserved.
|
||||
assert!(slur_curve_of(&constrained, id).is_some());
|
||||
// …and the unrendered dash style is surfaced, not silently dropped.
|
||||
assert!(
|
||||
constrained.diagnostics.iter().any(|d| {
|
||||
d.source == TypedObjectId::Slur(id)
|
||||
&& d.kind == LayoutDiagnosticKind::SlurLineStyleNotRendered
|
||||
}),
|
||||
"a dashed slur surfaces a SlurLineStyleNotRendered diagnostic"
|
||||
// The authored line pattern is carried on the drawn curve — rendered
|
||||
// faithfully, not deferred to a diagnostic.
|
||||
assert_eq!(
|
||||
slur_curve_of(&constrained, dashed_id)
|
||||
.expect("dashed slur draws")
|
||||
.line,
|
||||
LineStyle::Dashed
|
||||
);
|
||||
assert_eq!(
|
||||
slur_curve_of(&constrained, solid_id)
|
||||
.expect("solid slur draws")
|
||||
.line,
|
||||
LineStyle::Solid
|
||||
);
|
||||
// No line-style diagnostic remains — the style is rendered, not surfaced.
|
||||
assert!(constrained
|
||||
.diagnostics
|
||||
.iter()
|
||||
.all(|d| d.source != TypedObjectId::Slur(dashed_id)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -638,6 +638,7 @@ mod tests {
|
|||
thickness: crate::StaffSpace(0.2),
|
||||
layer: 0,
|
||||
style: crate::GlyphStyle { rgba: 0 },
|
||||
line: epiphany_core::LineStyle::Solid,
|
||||
};
|
||||
let map = RenderIR {
|
||||
primitives: vec![],
|
||||
|
|
|
|||
|
|
@ -164,4 +164,5 @@ pub use vertical_band::{inter_staff_gap_id, VerticalBand, VerticalBandId, Vertic
|
|||
pub use epiphany_ops::OperationKindTag;
|
||||
// `StemDirection` (Agent B) is the payload of `EngravingDecisionKind::StemDirection`;
|
||||
// re-exported so callers constructing that decision need not also import from core.
|
||||
pub use epiphany_core::LineStyle;
|
||||
pub use epiphany_core::StemDirection;
|
||||
|
|
|
|||
|
|
@ -172,6 +172,11 @@ impl CanonicalEncode for ResolvedLayoutIR {
|
|||
encode_staff_space(out, curve.thickness);
|
||||
out.extend_from_slice(&curve.style.rgba.to_le_bytes());
|
||||
out.extend_from_slice(&curve.layer.to_le_bytes());
|
||||
out.push(match curve.line {
|
||||
epiphany_core::LineStyle::Solid => 0,
|
||||
epiphany_core::LineStyle::Dashed => 1,
|
||||
epiphany_core::LineStyle::Dotted => 2,
|
||||
});
|
||||
}
|
||||
push_len(out, self.engraving_decisions.len());
|
||||
for decision in &self.engraving_decisions {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,9 @@
|
|||
use std::collections::BTreeMap;
|
||||
use std::fmt::Write as _;
|
||||
|
||||
use epiphany_layout_ir::{BoundingBox, Provenance, ResolvedGlyph, ResolvedLayoutIR, Transform2D};
|
||||
use epiphany_layout_ir::{
|
||||
BoundingBox, LineStyle, Provenance, ResolvedGlyph, ResolvedLayoutIR, Transform2D,
|
||||
};
|
||||
|
||||
use crate::font_subset_generated::{
|
||||
BRAVURA_SUBSET_FAMILY, BRAVURA_SUBSET_MIME, BRAVURA_SUBSET_OTF_BASE64,
|
||||
|
|
@ -370,7 +372,7 @@ pub fn render(resolved: &ResolvedLayoutIR, options: &RenderOptions) -> RenderOut
|
|||
let _ = writeln!(
|
||||
s,
|
||||
" <path d=\"M {} {} C {} {} {} {} {} {}\" \
|
||||
fill=\"none\" stroke=\"{}\" stroke-width=\"{}\"{}{}/>",
|
||||
fill=\"none\" stroke=\"{}\" stroke-width=\"{}\"{}{}{}/>",
|
||||
num(curve.p0.x.0),
|
||||
num(curve.p0.y.0),
|
||||
num(curve.p1.x.0),
|
||||
|
|
@ -381,6 +383,7 @@ pub fn render(resolved: &ResolvedLayoutIR, options: &RenderOptions) -> RenderOut
|
|||
num(curve.p3.y.0),
|
||||
stroke_fill,
|
||||
num(curve.thickness.0),
|
||||
dash_attrs(curve.line),
|
||||
opacity,
|
||||
prov,
|
||||
);
|
||||
|
|
@ -600,6 +603,18 @@ fn stroke_provenance_attrs(p: &Provenance) -> String {
|
|||
)
|
||||
}
|
||||
|
||||
/// The `stroke-dasharray` (and, for dotted, `stroke-linecap`) attribute for a
|
||||
/// curve's line pattern, in staff-space units (the viewBox is staff-space). A
|
||||
/// solid line adds nothing. Dashed is a dash/gap pair; dotted is round-capped
|
||||
/// zero-length dashes, drawing round dots of the stroke's own width.
|
||||
fn dash_attrs(line: LineStyle) -> &'static str {
|
||||
match line {
|
||||
LineStyle::Solid => "",
|
||||
LineStyle::Dashed => " stroke-dasharray=\"0.5 0.35\"",
|
||||
LineStyle::Dotted => " stroke-dasharray=\"0 0.28\" stroke-linecap=\"round\"",
|
||||
}
|
||||
}
|
||||
|
||||
/// `data-*` provenance attributes for a curve (a cubic-bézier primitive).
|
||||
fn curve_provenance_attrs(p: &Provenance) -> String {
|
||||
format!(
|
||||
|
|
@ -812,6 +827,44 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_curve_renders_as_a_path_and_a_dashed_curve_carries_a_dasharray() {
|
||||
use epiphany_layout_ir::Curve;
|
||||
let mut layout = stub_layout(11);
|
||||
let prov = layout.glyphs[0].provenance.clone();
|
||||
let make = |line| Curve {
|
||||
provenance: prov.clone(),
|
||||
p0: Point::new(0.0, 0.0),
|
||||
p1: Point::new(1.0, 2.0),
|
||||
p2: Point::new(3.0, 2.0),
|
||||
p3: Point::new(4.0, 0.0),
|
||||
thickness: StaffSpace(0.12),
|
||||
layer: 1,
|
||||
style: GlyphStyle { rgba: 0x0000_00ff },
|
||||
line,
|
||||
};
|
||||
// A solid curve: a stroked, unfilled <path> with no dasharray.
|
||||
layout.curves = vec![make(LineStyle::Solid)];
|
||||
let solid = render(&layout, &RenderOptions::default());
|
||||
assert!(solid.is_well_formed());
|
||||
assert_eq!(solid.stats.curve_count, 1);
|
||||
assert!(solid.svg.contains("<path d=\"M 0 0 C"));
|
||||
assert!(solid.svg.contains("data-kind=\"curve\""));
|
||||
assert!(
|
||||
!solid.svg.contains("stroke-dasharray"),
|
||||
"a solid curve has no dasharray"
|
||||
);
|
||||
// A dashed curve carries stroke-dasharray; a dotted one round-caps.
|
||||
layout.curves = vec![make(LineStyle::Dashed)];
|
||||
assert!(render(&layout, &RenderOptions::default())
|
||||
.svg
|
||||
.contains("stroke-dasharray=\"0.5 0.35\""));
|
||||
layout.curves = vec![make(LineStyle::Dotted)];
|
||||
let dotted = render(&layout, &RenderOptions::default()).svg;
|
||||
assert!(dotted.contains("stroke-dasharray=\"0 0.28\""));
|
||||
assert!(dotted.contains("stroke-linecap=\"round\""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_glyph_transform_is_applied_not_dropped() {
|
||||
let mut layout = stub_layout(11);
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@
|
|||
<line x1="7.565" y1="-20.8183" x2="44.7429" y2="-20.8183" stroke="#000000" stroke-width="0.13" data-prov="c146782303bbe4c29c6228235090facf" data-source-kind="3" data-kind="stroke"/>
|
||||
<path d="M 13.8247 -8.6267 C 15.3852 -7.56 16.9457 -7.56 18.5062 -8.6267" fill="none" stroke="#000000" stroke-width="0.12" data-prov="cf7d96019ed88156f3cc33bf116fbae3" data-source-kind="11" data-kind="curve"/>
|
||||
<path d="M 25.428 -14.0267 C 27.682 -16.6933 29.7736 -16.6933 31.5272 -14.0267" fill="none" stroke="#000000" stroke-width="0.12" data-prov="c366aecd1ef6e40cb1b3ffd2100eb3d8" data-source-kind="11" data-kind="curve"/>
|
||||
<path d="M 37.0313 -8.6267 C 38.5543 -7.56 39.8898 -7.56 41.0499 -8.6267" fill="none" stroke="#000000" stroke-width="0.12" data-prov="b6c086f751dd21ffa2520010201f057f" data-source-kind="11" data-kind="curve"/>
|
||||
<path d="M 37.0313 -8.6267 C 38.5543 -7.56 39.8898 -7.56 41.0499 -8.6267" fill="none" stroke="#000000" stroke-width="0.12" stroke-dasharray="0.5 0.35" data-prov="b6c086f751dd21ffa2520010201f057f" data-source-kind="11" data-kind="curve"/>
|
||||
<path d="M1.504 1.66C1.496 1.708 1.504 1.712 1.528 1.736C1.96 2.14 2.288 2.648 2.288 3.26C2.288 3.608 2.192 3.952 2.028 4.192C1.968 4.28 1.864 4.392 1.82 4.392C1.764 4.392 1.64 4.288 1.56 4.2C1.264 3.872 1.168 3.372 1.168 2.956C1.168 2.724 1.196 2.464 1.224 2.3C1.232 2.252 1.236 2.244 1.188 2.204C0.612 1.728 0 1.156 0 0.348C0 -0.348 0.476 -1.008 1.456 -1.008C1.548 -1.008 1.652 -1 1.732 -0.984C1.776 -0.976 1.784 -0.972 1.792 -1.02C1.84 -1.288 1.9 -1.636 1.9 -1.824C1.9 -2.416 1.5 -2.488 1.264 -2.488C1.048 -2.488 0.944 -2.424 0.944 -2.372C0.944 -2.344 0.98 -2.332 1.072 -2.304C1.196 -2.268 1.34 -2.16 1.34 -1.928C1.34 -1.708 1.2 -1.52 0.956 -1.52C0.688 -1.52 0.528 -1.732 0.528 -1.98C0.528 -2.24 0.684 -2.632 1.288 -2.632C1.556 -2.632 2.076 -2.512 2.076 -1.832C2.076 -1.604 2.004 -1.224 1.96 -0.976C1.952 -0.928 1.956 -0.932 2.012 -0.908C2.416 -0.748 2.684 -0.408 2.684 0.044C2.684 0.556 2.308 1.008 1.72 1.008C1.616 1.008 1.616 1.008 1.604 1.08ZM1.88 3.772C2.012 3.772 2.12 3.664 2.12 3.444C2.12 3 1.74 2.64 1.424 2.364C1.396 2.34 1.38 2.344 1.372 2.396C1.356 2.5 1.348 2.636 1.348 2.764C1.348 3.388 1.636 3.772 1.88 3.772ZM1.444 1.048C1.456 0.972 1.456 0.976 1.384 0.952C1.032 0.832 0.804 0.516 0.804 0.176C0.804 -0.184 0.992 -0.44 1.264 -0.532C1.296 -0.544 1.344 -0.556 1.372 -0.556C1.404 -0.556 1.42 -0.536 1.42 -0.512C1.42 -0.484 1.388 -0.472 1.36 -0.46C1.192 -0.388 1.072 -0.216 1.072 -0.032C1.072 0.196 1.228 0.368 1.472 0.436C1.536 0.452 1.544 0.448 1.552 0.404L1.752 -0.788C1.76 -0.832 1.756 -0.832 1.696 -0.844C1.632 -0.856 1.552 -0.864 1.472 -0.864C0.772 -0.864 0.32 -0.476 0.32 0.08C0.32 0.316 0.36 0.632 0.692 1.008C0.932 1.276 1.116 1.424 1.304 1.576C1.344 1.608 1.352 1.604 1.36 1.56ZM1.72 0.412C1.712 0.46 1.716 0.472 1.764 0.468C2.088 0.44 2.356 0.168 2.356 -0.184C2.356 -0.436 2.204 -0.64 1.98 -0.752C1.932 -0.776 1.924 -0.776 1.916 -0.728Z" transform="translate(8.5599 -12.3267)" fill="#000000" data-prov="2bc09f9490decea3e13f24459f1b64f4" data-source-kind="4" data-glyph="gClef" data-class="clef"/>
|
||||
<path d="M0.388 -0.5C0.744 -0.5 1.18 -0.172 1.18 0.168C1.18 0.372 1.02 0.5 0.792 0.5C0.352 0.5 0 0.176 0 -0.168C0 -0.376 0.172 -0.5 0.388 -0.5Z" transform="translate(13.0444 -14.3267)" fill="#000000" data-prov="870b54f8730bed8251f4f891a3c4b233" data-source-kind="1" data-glyph="noteheadBlack" data-class="notehead"/>
|
||||
<path d="M0.388 -0.5C0.744 -0.5 1.18 -0.172 1.18 0.168C1.18 0.372 1.02 0.5 0.792 0.5C0.352 0.5 0 0.176 0 -0.168C0 -0.376 0.172 -0.5 0.388 -0.5Z" transform="translate(15.1251 -14.3267)" fill="#000000" data-prov="5833135b23eaf581bccad90222f64e7e" data-source-kind="1" data-glyph="noteheadBlack" data-class="notehead"/>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 36 KiB |
|
|
@ -96,7 +96,7 @@
|
|||
<line x1="0" y1="0" x2="0" y2="0" stroke="#000000" stroke-width="0" data-prov="c183669ac91f35eb7a0040b48fde85ab" data-source-kind="25" data-kind="stroke"/>
|
||||
<path d="M 5.2 4.7 C 6.4 5.7667 7.6 5.7667 8.8 4.7" fill="none" stroke="#000000" stroke-width="0.12" data-prov="cf7d96019ed88156f3cc33bf116fbae3" data-source-kind="11" data-kind="curve"/>
|
||||
<path d="M 14.8 -0.7 C 16.5333 -3.3667 18.2667 -3.3667 20 -0.7" fill="none" stroke="#000000" stroke-width="0.12" data-prov="c366aecd1ef6e40cb1b3ffd2100eb3d8" data-source-kind="11" data-kind="curve"/>
|
||||
<path d="M 24.4 4.7 C 25.6 5.7667 26.8 5.7667 28 4.7" fill="none" stroke="#000000" stroke-width="0.12" data-prov="b6c086f751dd21ffa2520010201f057f" data-source-kind="11" data-kind="curve"/>
|
||||
<path d="M 24.4 4.7 C 25.6 5.7667 26.8 5.7667 28 4.7" fill="none" stroke="#000000" stroke-width="0.12" stroke-dasharray="0.5 0.35" data-prov="b6c086f751dd21ffa2520010201f057f" data-source-kind="11" data-kind="curve"/>
|
||||
<path d="M1.504 1.66C1.496 1.708 1.504 1.712 1.528 1.736C1.96 2.14 2.288 2.648 2.288 3.26C2.288 3.608 2.192 3.952 2.028 4.192C1.968 4.28 1.864 4.392 1.82 4.392C1.764 4.392 1.64 4.288 1.56 4.2C1.264 3.872 1.168 3.372 1.168 2.956C1.168 2.724 1.196 2.464 1.224 2.3C1.232 2.252 1.236 2.244 1.188 2.204C0.612 1.728 0 1.156 0 0.348C0 -0.348 0.476 -1.008 1.456 -1.008C1.548 -1.008 1.652 -1 1.732 -0.984C1.776 -0.976 1.784 -0.972 1.792 -1.02C1.84 -1.288 1.9 -1.636 1.9 -1.824C1.9 -2.416 1.5 -2.488 1.264 -2.488C1.048 -2.488 0.944 -2.424 0.944 -2.372C0.944 -2.344 0.98 -2.332 1.072 -2.304C1.196 -2.268 1.34 -2.16 1.34 -1.928C1.34 -1.708 1.2 -1.52 0.956 -1.52C0.688 -1.52 0.528 -1.732 0.528 -1.98C0.528 -2.24 0.684 -2.632 1.288 -2.632C1.556 -2.632 2.076 -2.512 2.076 -1.832C2.076 -1.604 2.004 -1.224 1.96 -0.976C1.952 -0.928 1.956 -0.932 2.012 -0.908C2.416 -0.748 2.684 -0.408 2.684 0.044C2.684 0.556 2.308 1.008 1.72 1.008C1.616 1.008 1.616 1.008 1.604 1.08ZM1.88 3.772C2.012 3.772 2.12 3.664 2.12 3.444C2.12 3 1.74 2.64 1.424 2.364C1.396 2.34 1.38 2.344 1.372 2.396C1.356 2.5 1.348 2.636 1.348 2.764C1.348 3.388 1.636 3.772 1.88 3.772ZM1.444 1.048C1.456 0.972 1.456 0.976 1.384 0.952C1.032 0.832 0.804 0.516 0.804 0.176C0.804 -0.184 0.992 -0.44 1.264 -0.532C1.296 -0.544 1.344 -0.556 1.372 -0.556C1.404 -0.556 1.42 -0.536 1.42 -0.512C1.42 -0.484 1.388 -0.472 1.36 -0.46C1.192 -0.388 1.072 -0.216 1.072 -0.032C1.072 0.196 1.228 0.368 1.472 0.436C1.536 0.452 1.544 0.448 1.552 0.404L1.752 -0.788C1.76 -0.832 1.756 -0.832 1.696 -0.844C1.632 -0.856 1.552 -0.864 1.472 -0.864C0.772 -0.864 0.32 -0.476 0.32 0.08C0.32 0.316 0.36 0.632 0.692 1.008C0.932 1.276 1.116 1.424 1.304 1.576C1.344 1.608 1.352 1.604 1.36 1.56ZM1.72 0.412C1.712 0.46 1.716 0.472 1.764 0.468C2.088 0.44 2.356 0.168 2.356 -0.184C2.356 -0.436 2.204 -0.64 1.98 -0.752C1.932 -0.776 1.924 -0.776 1.916 -0.728Z" transform="translate(0 1)" fill="#000000" data-prov="2bc09f9490decea3e13f24459f1b64f4" data-source-kind="4" data-glyph="gClef" data-class="clef"/>
|
||||
<path d="M0.388 -0.5C0.744 -0.5 1.18 -0.172 1.18 0.168C1.18 0.372 1.02 0.5 0.792 0.5C0.352 0.5 0 0.176 0 -0.168C0 -0.376 0.172 -0.5 0.388 -0.5Z" transform="translate(4.6 -1)" fill="#000000" data-prov="870b54f8730bed8251f4f891a3c4b233" data-source-kind="1" data-glyph="noteheadBlack" data-class="notehead"/>
|
||||
<path d="M0.388 -0.5C0.744 -0.5 1.18 -0.172 1.18 0.168C1.18 0.372 1.02 0.5 0.792 0.5C0.352 0.5 0 0.176 0 -0.168C0 -0.376 0.172 -0.5 0.388 -0.5Z" transform="translate(6.2 -1)" fill="#000000" data-prov="5833135b23eaf581bccad90222f64e7e" data-source-kind="1" data-glyph="noteheadBlack" data-class="notehead"/>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
|
|
@ -296,10 +296,8 @@ pub fn ten_measure_with_slurs(seed: u64) -> Score {
|
|||
end_event: events[12],
|
||||
kind: SlurKind::Editorial,
|
||||
curvature_override: None,
|
||||
// An authored dashed line — the Minimal tier draws it solid and
|
||||
// surfaces a `SlurLineStyleNotRendered` layout diagnostic (its dash
|
||||
// pattern is a higher-tier refinement), so the fixture exercises that
|
||||
// honest-deferral path.
|
||||
// An authored dashed line — rendered faithfully as a dashed cubic
|
||||
// (`stroke-dasharray`), so the fixture exercises the line-pattern path.
|
||||
style: SpanStyle {
|
||||
line: LineStyle::Dashed,
|
||||
thickness: None,
|
||||
|
|
|
|||
|
|
@ -359,6 +359,11 @@ pub fn gen_curve(rng: &mut Rng) -> Curve {
|
|||
style: GlyphStyle {
|
||||
rgba: rng.next_u64() as u32,
|
||||
},
|
||||
line: *rng.choose(&[
|
||||
epiphany_core::LineStyle::Solid,
|
||||
epiphany_core::LineStyle::Dashed,
|
||||
epiphany_core::LineStyle::Dotted,
|
||||
]),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue