Skip to main content

telar_renderer_core/
command.rs

1use std::sync::Arc;
2
3use geometry_core::{Point, Rect};
4
5use crate::{
6    BorderRadius, Color, ImageData, ImageFilter, PathData, PathStyle, RectStyle, Stroke, TextStyle,
7};
8
9/// One inline run of a rich-text paragraph: a slice of text with its own weight, slant, and colour. Paragraph
10/// metrics (font size, line height, wrapping, alignment) live on the [`DrawCommand::RichText`] `base` style,
11/// so a run overrides only what varies inline (bold, italic, a link's colour).
12#[derive(Debug, Clone, PartialEq)]
13pub struct TextRun {
14    pub text: Arc<str>,
15    pub weight: u16,
16    pub italic: bool,
17    pub color: Color,
18}
19
20#[derive(Debug, Clone)]
21pub enum DrawCommand {
22    Rect {
23        rect: Rect,
24        style: Arc<RectStyle>,
25    },
26    Text {
27        text: Arc<str>,
28        rect: Rect,
29        style: Arc<TextStyle>,
30    },
31    /// A paragraph of mixed-style runs shaped and wrapped as one (freedesktop notification body markup, etc.).
32    /// `base` supplies the shared metrics; each run carries its own weight/italic/colour.
33    RichText {
34        runs: Arc<[TextRun]>,
35        rect: Rect,
36        base: Arc<TextStyle>,
37    },
38    Image {
39        data: Arc<ImageData>,
40        rect: Rect,
41        filter: ImageFilter,
42    },
43    Line {
44        p1: Point,
45        p2: Point,
46        style: Stroke,
47    },
48    Path {
49        data: Arc<PathData>,
50        style: Arc<PathStyle>,
51    },
52    PushClip {
53        rect: Rect,
54        radius: BorderRadius,
55    },
56    PopClip,
57    PushMatrix {
58        matrix: [f32; 6],
59    },
60    PopMatrix,
61    PushLayer {
62        opacity: f32,
63        backdrop_blur: f32,
64    },
65    PopLayer,
66}
67
68impl PartialEq for DrawCommand {
69    fn eq(&self, other: &Self) -> bool {
70        match (self, other) {
71            (
72                DrawCommand::Rect {
73                    rect: r1,
74                    style: s1,
75                },
76                DrawCommand::Rect {
77                    rect: r2,
78                    style: s2,
79                },
80            ) => r1 == r2 && s1 == s2,
81            (
82                DrawCommand::Text {
83                    text: t1,
84                    rect: r1,
85                    style: s1,
86                },
87                DrawCommand::Text {
88                    text: t2,
89                    rect: r2,
90                    style: s2,
91                },
92            ) => *t1 == *t2 && r1 == r2 && s1 == s2,
93            (
94                DrawCommand::RichText {
95                    runs: u1,
96                    rect: r1,
97                    base: b1,
98                },
99                DrawCommand::RichText {
100                    runs: u2,
101                    rect: r2,
102                    base: b2,
103                },
104            ) => (Arc::ptr_eq(u1, u2) || u1 == u2) && r1 == r2 && b1 == b2,
105            (
106                DrawCommand::Image {
107                    data: d1,
108                    rect: r1,
109                    filter: f1,
110                },
111                DrawCommand::Image {
112                    data: d2,
113                    rect: r2,
114                    filter: f2,
115                },
116            ) => d1.id == d2.id && r1 == r2 && f1 == f2,
117            (
118                DrawCommand::Line {
119                    p1: p1a,
120                    p2: p2a,
121                    style: s1,
122                },
123                DrawCommand::Line {
124                    p1: p1b,
125                    p2: p2b,
126                    style: s2,
127                },
128            ) => p1a == p1b && p2a == p2b && s1 == s2,
129            (
130                DrawCommand::Path {
131                    data: d1,
132                    style: s1,
133                },
134                DrawCommand::Path {
135                    data: d2,
136                    style: s2,
137                },
138                // Pointer-equal is the cheap common case (same Arc reused); fall back to comparing geometry so a structurally-identical path rebuilt across frames still counts as unchanged (keeps scroll-blit / dirty-rect alive past path rebuilds).
139            ) => (Arc::ptr_eq(d1, d2) || d1 == d2) && s1 == s2,
140            (
141                DrawCommand::PushClip {
142                    rect: r1,
143                    radius: br1,
144                },
145                DrawCommand::PushClip {
146                    rect: r2,
147                    radius: br2,
148                },
149            ) => r1 == r2 && br1 == br2,
150            (DrawCommand::PopClip, DrawCommand::PopClip) => true,
151            (DrawCommand::PushMatrix { matrix: m1 }, DrawCommand::PushMatrix { matrix: m2 }) => {
152                m1 == m2
153            }
154            (DrawCommand::PopMatrix, DrawCommand::PopMatrix) => true,
155            (
156                DrawCommand::PushLayer {
157                    opacity: o1,
158                    backdrop_blur: b1,
159                },
160                DrawCommand::PushLayer {
161                    opacity: o2,
162                    backdrop_blur: b2,
163                },
164            ) => o1 == o2 && b1 == b2,
165            (DrawCommand::PopLayer, DrawCommand::PopLayer) => true,
166            _ => false,
167        }
168    }
169}