1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
//! This module implements the logic to manage graphic items included in a
//! `Grid` instance.
pub mod sixel;
use std::mem;
use std::sync::{Arc, Weak};
use parking_lot::Mutex;
use serde::{Deserialize, Serialize};
use crate::term::color::Rgb;
/// Max allowed dimensions (width, height) for the graphic, in pixels.
pub const MAX_GRAPHIC_DIMENSIONS: [usize; 2] = [4096, 4096];
/// Unique identifier for every graphic added to a grid.
#[derive(Serialize, Deserialize, Eq, PartialEq, Clone, Debug, Copy, Hash, PartialOrd, Ord)]
pub struct GraphicId(u64);
/// Reference to a texture stored in the display.
///
/// When all references to a single texture are removed, its identifier is
/// added to the remove queue.
#[derive(Clone, Debug)]
pub struct TextureRef {
/// Graphic identifier.
pub id: GraphicId,
/// Queue to track removed references.
pub remove_queue: Weak<Mutex<Vec<GraphicId>>>,
}
impl PartialEq for TextureRef {
fn eq(&self, t: &Self) -> bool {
// Ignore remove_queue.
self.id == t.id
}
}
impl Eq for TextureRef {}
impl Drop for TextureRef {
fn drop(&mut self) {
if let Some(remove_queue) = self.remove_queue.upgrade() {
remove_queue.lock().push(self.id);
}
}
}
/// Graphic data stored in a single cell.
#[derive(Eq, PartialEq, Clone, Debug)]
pub struct GraphicCell {
/// Texture to draw the graphic in this cell.
pub texture: Arc<TextureRef>,
/// Offset in the x direction.
pub offset_x: u16,
/// Offset in the y direction.
pub offset_y: u16,
}
impl GraphicCell {
/// Graphic identifier of the texture in this cell.
#[inline]
pub fn graphic_id(&self) -> GraphicId {
self.texture.id
}
}
/// Specifies the format of the pixel data.
#[derive(Serialize, Deserialize, Eq, PartialEq, Clone, Debug, Copy)]
pub enum ColorType {
/// 3 bytes per pixel (red, green, blue).
Rgb,
/// 4 bytes per pixel (red, green, blue, alpha).
Rgba,
}
/// Defines a single graphic read from the PTY.
#[derive(Serialize, Deserialize, Eq, PartialEq, Clone, Debug)]
pub struct GraphicData {
/// Graphics identifier.
pub id: GraphicId,
/// Width, in pixels, of the graphic.
pub width: usize,
/// Height, in pixels, of the graphic.
pub height: usize,
/// Color type of the pixels.
pub color_type: ColorType,
/// Pixels data.
pub pixels: Vec<u8>,
}
/// Queues to add or to remove the textures in the display.
pub struct UpdateQueues {
/// Graphics read from the PTY.
pub pending: Vec<GraphicData>,
/// Graphics removed from the grid.
pub remove_queue: Vec<GraphicId>,
}
/// Track changes in the grid to add or to remove graphics.
#[derive(Clone, Debug, Default)]
pub struct Graphics {
/// Last generated identifier.
pub last_id: u64,
/// New graphics, received from the PTY.
pub pending: Vec<GraphicData>,
/// Graphics removed from the grid.
pub remove_queue: Arc<Mutex<Vec<GraphicId>>>,
/// Shared palette for Sixel graphics.
pub sixel_shared_palette: Option<Vec<Rgb>>,
}
impl Graphics {
/// Generate a new graphic identifier.
pub fn next_id(&mut self) -> GraphicId {
self.last_id += 1;
GraphicId(self.last_id)
}
/// Get queues to update graphics in the grid.
///
/// If all queues are empty, it returns `None`.
pub fn take_queues(&mut self) -> Option<UpdateQueues> {
let mut remove_queue = self.remove_queue.lock();
if remove_queue.is_empty() && self.pending.is_empty() {
return None;
}
let remove_queue = mem::take(&mut *remove_queue);
Some(UpdateQueues { pending: mem::take(&mut self.pending), remove_queue })
}
}
|