Type: Strong type in a translucent brushed path keeps the path's opacity

Crisp and Strong reshape each edge pixel by the type's coverage, drawn
in black. Type in the art of a scatter brush on an undashed path drew
that coverage with the path's opacity folded in, so Strong made fully
covered pixels opaque at 50% path opacity. The coverage is now drawn
at full opacity; the pixels keep the folded opacity.

The evidence entry for the Anti-aliasing Method notes that scores and
hours are unchanged.
This commit is contained in:
dotCooCoo
2026-11-08 13:21:48 -08:00
parent 3146c7143d
commit 1bfd916d63
3 changed files with 40 additions and 1 deletions
+4
View File
@@ -484,7 +484,11 @@ impl Renderer {
AppearanceItem::Stroke(st) => st.opacity = 1.0,
}
}
// The coverage leaves out the opacity folded in from the object the type is drawn in
// (a translucent brushed path), which the pixels already take.
let folded = std::mem::replace(&mut r.alpha, 1.0);
let covered = draw(r, frame, &inked, &ink);
r.alpha = folded;
for (p, c) in pm.data_mut().iter_mut().zip(covered.data()) {
*p = edge_pixel(*p, c.a, t.anti_alias);
}
+35
View File
@@ -642,6 +642,41 @@ fn type_with_a_brush_stroke_is_drawn_as_sharp() {
}
}
/// Strong and Crisp type in the art of a scatter brush, on an undashed path at 50% opacity, keep
/// that opacity inside the characters: the coverage the method reshapes the edges by is drawn
/// without the path's opacity.
#[test]
fn type_in_a_translucent_scatter_brush_stroke_keeps_its_opacity() {
use vectorcraft_brush::{Brush, BrushKind, Scatter};
let draw = |m: TypeAntiAlias| {
let mut d = Document::new(f64::from(W), f64::from(H));
let mut t = TextObject::point(Point::new(0.0, 0.0), "H", CharStyle { size: 40.0, ..Default::default() });
t.anti_alias = m;
let art = Node::new(vectorcraft_doc::NodeId(0), NodeKind::Text(Box::new(t)));
let mut lib = vectorcraft_brush::library(&d);
lib.push(Brush { name: "Letters".into(), kind: BrushKind::Scatter(Scatter { art, spacing: (200.0, 200.0), ..Default::default() }) });
vectorcraft_brush::store(&mut d, &lib);
let mut ap = Appearance::basic(Paint::None, Paint::solid(Color::BLACK), 1.0);
if let Some(st) = ap.stroke_mut() {
st.brush = Some("Letters".into());
}
let line = vectorcraft_geom::shapes::line(Point::new(20.0, 45.0), Point::new(240.0, 45.0));
let mut n = Node::path(d.alloc_id(), line, ap);
n.opacity = 0.5;
let l = d.layers[0].id;
d.insert(Some(l), 0, n).unwrap();
alphas(&d, &RenderOptions::default())
};
let most = |a: &[u8]| a.iter().copied().max().unwrap_or(0);
let sharp = draw(TypeAntiAlias::Sharp);
assert!((126..=129).contains(&most(&sharp)), "half opaque: {}", most(&sharp));
for m in [TypeAntiAlias::Crisp, TypeAntiAlias::Strong] {
let drawn = draw(m);
assert!((126..=129).contains(&most(&drawn)), "{m:?} keeps the path's opacity: {}", most(&drawn));
assert_ne!(drawn, sharp, "{m:?} changes the edges");
}
}
/// On screen, type in a font the system doesn't have draws as Sharp draws it while Document
/// Setup highlights substituted fonts, and with its method when nothing is highlighted.
#[test]
+1 -1
View File
@@ -1037,7 +1037,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
The Character panel menu's Show Font Height Options shows a Set Font Height Reference dropdown under Font Size (`text.setFormat` or `text.setRangeStyle` `{fontHeightReference}`). With Em Box, the default, the font size is the size of the em square; with Cap Height, x-Height or ICF Box, the characters are set at the em size at which the font's OS/2 cap height, its x height or the height of its ideographic character face equals the font size. With a font that has no such value, or one outside 0.1 to 2 em, the size measures the em box. SVG, PDF and legacy `.ai` export and the CSS Properties rules write the em size the characters are drawn at, and DXF export writes 0.7 times that em size as each TEXT entity's height (group 40, the height of its capitals). Behavior reference: [Vary font height](https://web.archive.org/web/20251118174722/https://helpx.adobe.com/illustrator/desktop/design-with-text/edit-format-text/vary-font-height.html).
The Every-line Composer composes a paragraph whose characters differ in line metrics (type size, font, leading or vertical scale, or an inline graphic taller than the text) in rectangular area type, rows and columns included. In area type of another shape, or with text wrap, such a paragraph is broken with the Single-line Composer.
The Character panel's Small Caps, Superscript and Subscript buttons and the panel menu's items of the same names turn small caps and the superscript or subscript position on and off for the selected type, or for the text the Type tool has selected (`text.setFormat` or `text.setRangeStyle` `{smallCaps, position}`), in Document Setup's proportions. Turning Superscript on turns Subscript off, and turning Subscript on turns Superscript off. A button or item shows as on when the first selected character (at a caret, the character before it) has its attribute.
The Character panel's Anti-aliasing Method dropdown, under Character Rotation, sets how the edges of the selected type objects are drawn as pixels (`text.setFormat {antiAlias}`), for the whole object, with each frame of a thread keeping its own method, on the canvas, in raster exports and when the type is rasterized. VectorCraft defines the methods: Sharp, the default, draws edges as before; None paints a pixel only where the type covers at least half of it; Crisp shows a pixel covered by a share c at `2c - 0.5`, and Strong shows it at `2c`, each kept between 0 and 1. SVG, PDF and EPS export are unchanged.
The Character panel's Anti-aliasing Method dropdown, under Character Rotation, sets how the edges of the selected type objects are drawn as pixels (`text.setFormat {antiAlias}`), for the whole object, with each frame of a thread keeping its own method, on the canvas, in raster exports and when the type is rasterized. VectorCraft defines the methods: Sharp, the default, draws edges as before; None paints a pixel only where the type covers at least half of it; Crisp shows a pixel covered by a share c at `2c - 0.5`, and Strong shows it at `2c`, each kept between 0 and 1. SVG, PDF and EPS export are unchanged. Scores and hours unchanged.
The OpenType panel's Stylistic Alternates and Titling Alternates checkboxes turn `salt` and `titl` on and off for the selected type, and its Figure menu lists Default Figure, Tabular Lining, Proportional Lining, Proportional Oldstyle and Tabular Oldstyle; Proportional Lining sets `pnum` and `lnum` and turns `tnum` and `onum` off, Tabular Lining turns `pnum` off and keeps `lnum`, Proportional Oldstyle turns `lnum` off and keeps `pnum`, and Default Figure and Tabular Oldstyle turn `pnum` and `lnum` off. Behavior reference: [Format text with OpenType features](https://helpx.adobe.com/illustrator/desktop/design-with-text/special-characters-glyphs/format-text-with-opentype-features.html) and [Use swashes, titling alternates, or stylistic alternates](https://helpx.adobe.com/illustrator/desktop/design-with-text/special-characters-glyphs/use-swashes-titling-alternates-or-stylistic-alternates.html) (public documentation). Tests: `panels::opentype::tests`.
The OpenType panel's Position menu lists Default Position, Superscript, Subscript, Numerator and Denominator, as [Format text with OpenType features](https://helpx.adobe.com/illustrator/desktop/design-with-text/special-characters-glyphs/format-text-with-opentype-features.html) describes; Superscript, Subscript, Numerator and Denominator set `sups`, `subs`, `numr` and `dnom` for the selected type and turn the other three off, and Default Position turns all four off. The menu shows Mixed when the characters it acts on differ, and an entry chosen then applies to all of them. These two rules are VectorCraft's own, as is setting the feature on type whose font lacks the glyphs, which then draws unchanged. The panel's menus and checkboxes change only their own features on each selected character, so characters keep their other OpenType features (`text.setStyle` and `text.setRangeStyle` `{featureChanges}`). Tests: `panels::opentype::tests`, `features::tests::numerators_and_denominators_are_kept_and_shaped`.
The Glyphs panel's Show menu and panel menu have Alternates for Current Selection, as [Replace characters with alternate glyphs](https://helpx.adobe.com/illustrator/desktop/design-with-text/special-characters-glyphs/replace-characters-with-alternate-glyphs.html) describes: the grid lists the alternate glyphs of the character selected with the Type tool, and a double-click draws that character with the glyph as one undo step (`text.glyphAlternates`, `text.setGlyphAlternate`). The alternates come from the font's `GSUB` single and alternate substitutions of `aalt`, then `salt`, `ss01` to `ss20`, `swsh`, `cv01` to `cv99` and a few other alternate features, each glyph once. The text keeps the character, native files keep the choice with the face it was made in, and type set in another font or version draws the default glyph. The list uses the font of the character's text even when the panel browses another font, and the panel shows a note when the character has no alternates, its font is missing or no character is selected; these rules are VectorCraft's own. Tests: `panels::glyphs::tests`, `tests::alternates`, `tests::textedit::a_glyph_alternate_replaces_one_character_through_undo_and_reopen`.