1use ravenrs_core::{Color, ImageQuad, Point, Quad, Rect, Scene};
4use ravenrs_text::TextSystem;
5
6use crate::document::{Item, Page};
7use crate::engine::text_attrs;
8
9pub fn paint_page(page: &Page, text: &mut TextSystem, scene: &mut Scene, origin: Point, scale: f32) {
12 let at = |x: f32, y: f32| Point::new(origin.x + x * scale, origin.y + y * scale);
13 let rect = |r: &Rect| {
14 Rect::from_origin_size(
15 at(r.x(), r.y()),
16 ravenrs_core::Size::new(r.width() * scale, r.height() * scale),
17 )
18 };
19 let paper = Rect::new(origin.x, origin.y, page.width * scale, page.height * scale);
20 scene.push_quad(Quad::new(paper, Color::WHITE).shadow(ravenrs_core::Shadow {
21 offset: Point::new(0.0, 2.0),
22 blur: 12.0,
23 color: Color::rgba(0.0, 0.0, 0.0, 0.35),
24 }));
25 scene.push_clip(paper);
26 for item in &page.items {
27 match item {
28 Item::Rect { rect: r, fill, stroke, radius } => {
29 let mut q = Quad::new(rect(r), fill.unwrap_or(Color::TRANSPARENT)).radius(radius * scale);
30 if let Some((w, c)) = stroke {
31 q = q.border((w * scale).max(0.5), *c);
32 }
33 scene.push_quad(q);
34 }
35 Item::Ellipse { rect: r, fill, stroke } => {
36 let r = rect(r);
37 let mut q =
38 Quad::new(r, fill.unwrap_or(Color::TRANSPARENT)).radius(r.width().min(r.height()) / 2.0);
39 if let Some((w, c)) = stroke {
40 q = q.border((w * scale).max(0.5), *c);
41 }
42 scene.push_quad(q);
43 }
44 Item::Line { from, to, width, color } => {
45 let (a, b) = (at(from.x, from.y), at(to.x, to.y));
48 let w = (width * scale).max(0.75);
49 let r = if (a.y - b.y).abs() < 0.01 {
50 Rect::new(a.x.min(b.x), a.y - w / 2.0, (a.x - b.x).abs(), w)
51 } else if (a.x - b.x).abs() < 0.01 {
52 Rect::new(a.x - w / 2.0, a.y.min(b.y), w, (a.y - b.y).abs())
53 } else {
54 let steps = ((b.x - a.x).hypot(b.y - a.y) / w).ceil().max(1.0) as usize;
56 for i in 0..=steps {
57 let t = i as f32 / steps as f32;
58 let p = Point::new(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t);
59 scene.push_quad(
60 Quad::new(Rect::new(p.x - w / 2.0, p.y - w / 2.0, w, w), *color).radius(w / 2.0),
61 );
62 }
63 continue;
64 };
65 scene.push_quad(Quad::new(r, *color));
66 }
67 Item::Text(t) => {
68 scene.push_clip(rect(&t.clip));
69 let attrs = text_attrs(t.size * scale, t.bold);
70 let attrs = ravenrs_text::TextAttrs { line_height: t.line_height * scale, ..attrs };
71 for line in &t.lines {
72 let mut layout = text.layout(&line.text, &attrs);
73 layout.measure(None);
74 layout.paint(at(line.x, line.top), t.color, scene);
75 }
76 scene.pop_clip();
77 }
78 Item::Image { rect: r, clip, image } => {
79 scene.push_clip(rect(clip));
80 scene.push_image(ImageQuad::new(rect(r), image.pixels().clone()));
81 scene.pop_clip();
82 }
83 Item::Vector { rect: r, shapes } => {
84 if let Some(image) = crate::vector::rasterize(shapes, *r, scale * 2.0) {
86 scene.push_image(ImageQuad::new(rect(r), image));
87 }
88 }
89 Item::Link { .. } | Item::Bookmark { .. } => {}
91 }
92 }
93 scene.pop_clip();
94}