mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-26 02:37:01 -06:00
The renderer kept the rasters of an object's drop shadows, outer glows and filtered content (Gaussian Blur, Feather and the Photoshop-style filters), and drew them again while the object, the zoom and rotation and the ink plane stayed the same. The content drawn into a raster also reads things outside the object: patterns, symbols, brushes, images, document, layer and color settings, the knockout a group inherits, the fonts, and the options the frame is drawn with. When one of them changed, a renderer that had drawn the object went on drawing the raster it had kept, made from the old values. Each kept raster now records what its content was drawn from: which of those things the object reads, found by walking the object when the raster is made, and a hash of their values then. The renderer draws the raster only while that hash is the same in the current frame. Once a frame, the renderer hashes the document's patterns, symbols and images. It hashes their art and pixels by the addresses of their shared values, and it keeps weak references to those values while a raster made with them is kept, so no other value can take one of those addresses. A filtered raster also records the color channels its filters split, and under De-Interlace the raster resolution. A temporary release test timed the inputs of 400 kept rasters at about 10 microseconds a frame.
88 lines
4.9 KiB
Rust
88 lines
4.9 KiB
Rust
//! Type redraws in a font that becomes available while it is on screen (fonts added, Refresh Font
|
|
//! List).
|
|
|
|
use vectorcraft_doc::text::{CharStyle, TextObject};
|
|
use vectorcraft_doc::{Node, NodeKind};
|
|
use vectorcraft_geom::Point;
|
|
|
|
use super::*;
|
|
|
|
/// The bundled Source Serif 4 renamed `family` (as long as the original name).
|
|
fn serif_as(family: &str) -> Vec<u8> {
|
|
let mut data = include_bytes!("../../../assets/fonts/SourceSerif4-Regular.ttf").to_vec();
|
|
let utf16 = |s: &str| s.encode_utf16().flat_map(u16::to_be_bytes).collect::<Vec<u8>>();
|
|
for (from, to) in [(utf16("Source Serif 4"), utf16(family)), (b"Source Serif 4".to_vec(), family.as_bytes().to_vec())] {
|
|
assert_eq!(from.len(), to.len());
|
|
let mut i = 0;
|
|
while let Some(at) = data[i..].windows(from.len()).position(|w| w == from) {
|
|
data[i + at..i + at + to.len()].copy_from_slice(&to);
|
|
i += at + to.len();
|
|
}
|
|
}
|
|
data
|
|
}
|
|
|
|
#[test]
|
|
fn type_redraws_when_its_font_becomes_available() {
|
|
const FAMILY: &str = "Arrival Serif4";
|
|
let mut d = Document::new(300.0, 150.0);
|
|
let style = CharStyle { size: 60.0, font_family: FAMILY.into(), ..Default::default() };
|
|
let mut n = Node::new(NodeId(0), NodeKind::Text(Box::new(TextObject::point(Point::new(10.0, 100.0), "Hamburg", style))));
|
|
n.id = d.alloc_id();
|
|
let l = d.layers[0].id;
|
|
d.insert(Some(l), 0, n).unwrap();
|
|
let opts = RenderOptions { background: Some([255, 255, 255, 255]), ..Default::default() };
|
|
let mut r = Renderer::new();
|
|
let before = r.render(&d, 300, 150, Affine::IDENTITY, &opts).pixels;
|
|
assert!(vectorcraft_text::FontDb::global().add_font(serif_as(FAMILY)) > 0);
|
|
let after = r.render(&d, 300, 150, Affine::IDENTITY, &opts).pixels;
|
|
assert_ne!(before, after, "drawn in the font that arrived");
|
|
assert_eq!(after, Renderer::new().render(&d, 300, 150, Affine::IDENTITY, &opts).pixels, "as a new renderer draws it");
|
|
}
|
|
|
|
/// Type with raster effects redraws in a font that becomes available: its drop shadow and its
|
|
/// blurred content are made again.
|
|
#[test]
|
|
fn type_with_raster_effects_redraws_when_its_font_becomes_available() {
|
|
const FAMILY: &str = "Raster Serif 4";
|
|
let mut d = Document::new(300.0, 150.0);
|
|
let l = d.layers[0].id;
|
|
let effects =
|
|
[("stylize.dropShadow", serde_json::json!({"x": 4, "y": 4, "blur": 1, "opacity": 100})), ("blur.gaussian", serde_json::json!({"radius": 1}))];
|
|
for (i, (id, params)) in effects.into_iter().enumerate() {
|
|
let style = CharStyle { size: 50.0, font_family: FAMILY.into(), ..Default::default() };
|
|
let mut n = Node::new(d.alloc_id(), NodeKind::Text(Box::new(TextObject::point(Point::new(10.0, 60.0 + 70.0 * i as f64), "Hamburg", style))));
|
|
n.appearance.effects.push(vectorcraft_doc::Effect { id: id.into(), params, visible: true });
|
|
d.insert(Some(l), i, n).unwrap();
|
|
}
|
|
let opts = RenderOptions { background: Some([255, 255, 255, 255]), ..Default::default() };
|
|
let mut r = Renderer::new();
|
|
let before = r.render(&d, 300, 150, Affine::IDENTITY, &opts).pixels;
|
|
assert!(vectorcraft_text::FontDb::global().add_font(serif_as(FAMILY)) > 0);
|
|
let after = r.render(&d, 300, 150, Affine::IDENTITY, &opts).pixels;
|
|
assert_ne!(before, after, "drawn in the font that arrived");
|
|
assert_eq!(after, Renderer::new().render(&d, 300, 150, Affine::IDENTITY, &opts).pixels, "as a new renderer draws it");
|
|
}
|
|
|
|
/// Type with a geometry effect in a symbol's art redraws in a font that becomes available: the art
|
|
/// kept for the instance is placed again when the fonts change.
|
|
#[test]
|
|
fn symbol_type_redraws_when_its_font_becomes_available() {
|
|
const FAMILY: &str = "Placed Serif 4";
|
|
let mut d = Document::new(300.0, 150.0);
|
|
let style = CharStyle { size: 60.0, font_family: FAMILY.into(), ..Default::default() };
|
|
let mut t = Node::new(d.alloc_id(), NodeKind::Text(Box::new(TextObject::point(Point::new(-140.0, 25.0), "Hamburg", style))));
|
|
t.appearance.effects.push(vectorcraft_doc::Effect { id: "distort.transform".into(), params: serde_json::json!({"moveH": 0.0}), visible: true });
|
|
let art = Node::group(d.alloc_id(), vec![Arc::new(t)]);
|
|
d.symbols.push(vectorcraft_doc::Symbol { name: "Word".into(), art: Arc::new(art) });
|
|
let (l, id) = (d.layers[0].id, d.alloc_id());
|
|
d.insert(Some(l), 0, Node::new(id, NodeKind::SymbolInstance { symbol: "Word".into(), xf: Affine::translate((150.0, 75.0)) })).unwrap();
|
|
let opts = RenderOptions { background: Some([255, 255, 255, 255]), ..Default::default() };
|
|
let mut r = Renderer::new();
|
|
let before = r.render(&d, 300, 150, Affine::IDENTITY, &opts).pixels;
|
|
assert!(vectorcraft_text::FontDb::global().add_font(serif_as(FAMILY)) > 0);
|
|
let after = r.render(&d, 300, 150, Affine::IDENTITY, &opts).pixels;
|
|
assert_ne!(before, after, "drawn in the font that arrived");
|
|
assert_eq!(after, Renderer::new().render(&d, 300, 150, Affine::IDENTITY, &opts).pixels, "as a new renderer draws it");
|
|
}
|