mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-10 03:01:33 +00:00
Character: non-Sharp type keeps its character stroke outlines
`main` now passes `draw_text_geom` the kept glyph geometry as an `Arc` and whether `texts` keeps it, so that character stroke outlines are expanded once. `draw_type_edges` and `draw_type_pixels` pass both on to their offscreen drawings, so None, Crisp and Strong type with a character stroke expands the stroke once for both drawings, as Sharp type does. The new test `crisp_type_keeps_its_character_stroke_outline` checks that one outline is kept and that the pixels match a renderer that keeps no glyph geometry. `a_pan_draws_the_type_from_the_kept_pixels` now holds `fonts_steady`, as the other tests of what a renderer keeps between frames do.
This commit is contained in:
@@ -1987,7 +1987,7 @@ impl Renderer {
|
||||
self.draw_inlines(ctx, f, t, g);
|
||||
return;
|
||||
}
|
||||
if t.anti_alias != TypeAntiAlias::Sharp && self.draw_type_edges(ctx, f, n, t, g) {
|
||||
if t.anti_alias != TypeAntiAlias::Sharp && self.draw_type_edges(ctx, f, n, t, g, kept) {
|
||||
return;
|
||||
}
|
||||
let tb = t.xf.transform_rect_bbox(g.bounds);
|
||||
@@ -2078,7 +2078,8 @@ impl Renderer {
|
||||
/// smoothing and what the type reads ([`Self::raster_inputs`]) are unchanged, the output has
|
||||
/// moved by whole pixels, and the kept pixels hold every pixel the frame needs. After a pan,
|
||||
/// the kept pixels are placed moved by it; after a pan that brings more of the type into view,
|
||||
/// the type is drawn offscreen again.
|
||||
/// the type is drawn offscreen again. The outlines of its character strokes are cached when
|
||||
/// `g` is kept in `texts` (`geom_kept`).
|
||||
///
|
||||
/// Returns false, having drawn nothing, for type that is drawn as Sharp draws it: type with
|
||||
/// inline graphics, type with color glyphs (bitmap or COLR), type whose own fills or strokes
|
||||
@@ -2087,7 +2088,7 @@ impl Renderer {
|
||||
/// offscreen, those would blend with nothing or take the method on art that is not the
|
||||
/// characters'. It also returns false for type whose offscreen drawing would be more than
|
||||
/// [`MAX_RASTER_SIDE`] pixels a side.
|
||||
fn draw_type_edges(&mut self, ctx: &mut RenderContext, f: &Frame, n: &Node, t: &TextObject, g: &TextGeom) -> bool {
|
||||
fn draw_type_edges(&mut self, ctx: &mut RenderContext, f: &Frame, n: &Node, t: &TextObject, g: &Arc<TextGeom>, geom_kept: bool) -> bool {
|
||||
if proof::overprints(f.opts) && t.runs.iter().any(|r| r.style.overprint_fill || r.style.overprint_stroke) {
|
||||
return false;
|
||||
}
|
||||
@@ -2170,7 +2171,7 @@ impl Renderer {
|
||||
let (image, ox, oy) = match kept {
|
||||
Some(kept) => kept,
|
||||
None => {
|
||||
let pm = self.draw_type_pixels(&frame, n, t, g, (w, h), threshold);
|
||||
let pm = self.draw_type_pixels(&frame, n, t, g, geom_kept, (w, h), threshold);
|
||||
self.stats.type_edges += 1;
|
||||
let image = Arc::new(pm);
|
||||
if let Some(inputs) = inputs {
|
||||
@@ -2194,12 +2195,23 @@ impl Renderer {
|
||||
|
||||
/// The pixels of type `t` of node `n` (laid out in `g`) with its anti-aliasing method, drawn
|
||||
/// offscreen in `frame` on `w` × `h` pixels with edge threshold `threshold`
|
||||
/// ([`Self::draw_type_edges`]).
|
||||
fn draw_type_pixels(&mut self, frame: &Frame, n: &Node, t: &TextObject, g: &TextGeom, (w, h): (u16, u16), threshold: Option<u8>) -> Pixmap {
|
||||
/// ([`Self::draw_type_edges`]). The outlines of its character strokes are cached when `g` is
|
||||
/// kept in `texts` (`kept`).
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn draw_type_pixels(
|
||||
&mut self,
|
||||
frame: &Frame,
|
||||
n: &Node,
|
||||
t: &TextObject,
|
||||
g: &Arc<TextGeom>,
|
||||
kept: bool,
|
||||
(w, h): (u16, u16),
|
||||
threshold: Option<u8>,
|
||||
) -> Pixmap {
|
||||
let draw = |r: &mut Self, frame: &Frame, n: &Node, t: &TextObject| {
|
||||
let mut off = single_threaded_context(w, h);
|
||||
off.set_aliasing_threshold(threshold);
|
||||
r.inside_layer(|r| r.draw_text_geom(&mut off, frame, n, t, g));
|
||||
r.inside_layer(|r| r.draw_text_geom(&mut off, frame, n, t, g, kept));
|
||||
off.flush();
|
||||
let mut pm = Pixmap::new(w, h);
|
||||
off.render(&mut pm, &mut r.resources);
|
||||
|
||||
@@ -567,6 +567,29 @@ fn the_offscreen_drawing_takes_in_the_strokes_reach() {
|
||||
assert!(near(past(&own, &t), (90.0, 90.0)), "the object's own stroke after the characters': {:?}", past(&own, &t));
|
||||
}
|
||||
|
||||
/// Crisp type with a character stroke expands the stroke once for both of its offscreen drawings,
|
||||
/// and keeps the outline as Sharp type does. Its pixels are those of a renderer that keeps no
|
||||
/// glyph geometry, which expands the stroke in every drawing.
|
||||
#[test]
|
||||
fn crisp_type_keeps_its_character_stroke_outline() {
|
||||
let _fonts = crate::tests_fontchange::fonts_steady();
|
||||
let mut d = page(TypeAntiAlias::Crisp, None);
|
||||
let id = d.layers[0].children().and_then(|c| c.first()).map(|n| n.id).unwrap();
|
||||
if let Some(Node { kind: NodeKind::Text(t), .. }) = d.node_mut(id) {
|
||||
t.runs[0].style.stroke = Paint::solid(Color::BLACK);
|
||||
t.runs[0].style.stroke_width = 1.0;
|
||||
}
|
||||
let opts = RenderOptions::default();
|
||||
let mut r = Renderer::new();
|
||||
let pixels = r.render(&d, W, H, Affine::IDENTITY, &opts).pixels;
|
||||
assert_eq!(r.stats.type_edges, 1, "the type is drawn offscreen");
|
||||
assert_eq!(r.char_strokes.len(), 1, "one outline for the one run's stroke, used by both drawings");
|
||||
let mut uncached = Renderer::new();
|
||||
uncached.texts = FrameCache::new(0, 0);
|
||||
assert!(uncached.render(&d, W, H, Affine::IDENTITY, &opts).pixels == pixels, "the kept outline draws the same pixels");
|
||||
assert_eq!(uncached.char_strokes.len(), 0);
|
||||
}
|
||||
|
||||
/// Area type draws its punctuation outside its frame with Optical Margin Alignment, and None type
|
||||
/// draws it there too.
|
||||
#[test]
|
||||
@@ -593,6 +616,7 @@ fn type_outside_its_frame_is_drawn() {
|
||||
/// the type again.
|
||||
#[test]
|
||||
fn a_pan_draws_the_type_from_the_kept_pixels() {
|
||||
let _fonts = crate::tests_fontchange::fonts_steady();
|
||||
let opts = RenderOptions::default();
|
||||
let fonts = || vectorcraft_text::FontDb::global().generation();
|
||||
// How many type objects a renderer drew offscreen for `b` in `second` after drawing `a` in
|
||||
|
||||
Reference in New Issue
Block a user