xref: /DragonOS/kernel/src/libs/lib_ui/textui.rs (revision f9fe30be89e89499aad4ef52b4648986bef5a7d8)
1 use crate::{
2     driver::{
3         serial::serial8250::send_to_default_serial8250_port, tty::virtual_terminal::vc_manager,
4         video::video_refresh_manager,
5     },
6     libs::{
7         lib_ui::font::FONT_8x16,
8         rwlock::RwLock,
9         spinlock::{SpinLock, SpinLockGuard},
10     },
11 };
12 use alloc::{boxed::Box, collections::LinkedList, string::ToString};
13 use alloc::{sync::Arc, vec::Vec};
14 use core::{
15     fmt::Debug,
16     intrinsics::unlikely,
17     ops::{Add, AddAssign, Sub},
18     ptr::copy_nonoverlapping,
19     sync::atomic::{AtomicBool, AtomicI32, AtomicU32, Ordering},
20 };
21 use log::{debug, info};
22 use system_error::SystemError;
23 
24 use super::{
25     screen_manager::{
26         scm_register, ScmBuffer, ScmBufferInfo, ScmFramworkType, ScmUiFramework,
27         ScmUiFrameworkMetadata,
28     },
29     textui_no_alloc::no_init_textui_putchar_window,
30 };
31 
32 /// 声明全局的TEXTUI_FRAMEWORK
33 static mut __TEXTUI_FRAMEWORK: Option<Arc<TextUiFramework>> = None;
34 
35 /// 每个字符的宽度和高度(像素)
36 pub const TEXTUI_CHAR_WIDTH: u32 = 8;
37 
38 pub const TEXTUI_CHAR_HEIGHT: u32 = 16;
39 
40 pub static mut TEXTUI_IS_INIT: bool = false;
41 
42 static ENABLE_PUT_TO_WINDOW: AtomicBool = AtomicBool::new(false);
43 
44 /// 启用将文本输出到窗口的功能。
textui_enable_put_to_window()45 pub fn textui_enable_put_to_window() {
46     ENABLE_PUT_TO_WINDOW.store(true, Ordering::SeqCst);
47 }
48 
49 /// 禁用将文本输出到窗口的功能。
textui_disable_put_to_window()50 pub fn textui_disable_put_to_window() {
51     ENABLE_PUT_TO_WINDOW.store(false, Ordering::SeqCst);
52 }
53 
54 /// 检查是否启用了将文本输出到窗口的功能。
55 ///
56 /// # 返回
57 /// 如果启用了将文本输出到窗口的功能,则返回 `true`,否则返回 `false`。
textui_is_enable_put_to_window() -> bool58 pub fn textui_is_enable_put_to_window() -> bool {
59     ENABLE_PUT_TO_WINDOW.load(Ordering::SeqCst)
60 }
61 
62 /// 获取TEXTUI_FRAMEWORK的可变实例
textui_framework() -> Arc<TextUiFramework>63 pub fn textui_framework() -> Arc<TextUiFramework> {
64     unsafe {
65         return __TEXTUI_FRAMEWORK
66             .as_ref()
67             .expect("Textui framework has not been initialized yet!")
68             .clone();
69     }
70 }
71 
72 /// 初始化TEXTUI_FRAMEWORK
textui_framwork_init()73 fn textui_framwork_init() {
74     if unsafe { __TEXTUI_FRAMEWORK.is_none() } {
75         info!("textuiframework init");
76         let metadata = ScmUiFrameworkMetadata::new("TextUI".to_string(), ScmFramworkType::Text);
77         debug!("textui metadata: {:?}", metadata);
78         // 为textui框架生成第一个窗口
79         let vlines_num = (metadata.buf_info().height() / TEXTUI_CHAR_HEIGHT) as usize;
80 
81         let chars_num = (metadata.buf_info().width() / TEXTUI_CHAR_WIDTH) as usize;
82 
83         let initial_window = TextuiWindow::new(
84             WindowFlag::TEXTUI_CHROMATIC,
85             vlines_num as i32,
86             chars_num as i32,
87         );
88 
89         let current_window: Arc<SpinLock<TextuiWindow>> = Arc::new(SpinLock::new(initial_window));
90 
91         let default_window = current_window.clone();
92 
93         // 生成窗口链表,并把上面窗口添加进textui框架的窗口链表中
94         let window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>> =
95             Arc::new(SpinLock::new(LinkedList::new()));
96         window_list.lock().push_back(current_window.clone());
97 
98         unsafe {
99             __TEXTUI_FRAMEWORK = Some(Arc::new(TextUiFramework::new(
100                 metadata,
101                 window_list,
102                 current_window,
103                 default_window,
104             )))
105         };
106 
107         scm_register(textui_framework()).expect("register textui framework failed");
108         debug!("textui framework init success");
109 
110         send_to_default_serial8250_port("\ntext ui initialized\n\0".as_bytes());
111         unsafe { TEXTUI_IS_INIT = true };
112     } else {
113         panic!("Try to init TEXTUI_FRAMEWORK twice!");
114     }
115 }
116 // window标志位
117 bitflags! {
118     pub struct WindowFlag: u8 {
119         // 采用彩色字符
120         const TEXTUI_CHROMATIC = 1 << 0;
121     }
122 }
123 
124 /**
125  * @brief 黑白字符对象
126  *
127  */
128 #[derive(Clone, Debug)]
129 struct TextuiCharNormal {
130     _data: u8,
131 }
132 
133 #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Default)]
134 pub struct LineId(i32);
135 impl LineId {
new(num: i32) -> Self136     pub fn new(num: i32) -> Self {
137         LineId(num)
138     }
139 
check(&self, max: i32) -> bool140     pub fn check(&self, max: i32) -> bool {
141         self.0 < max && self.0 >= 0
142     }
143 
data(&self) -> i32144     pub fn data(&self) -> i32 {
145         self.0
146     }
147 }
148 impl Add<i32> for LineId {
149     type Output = LineId;
add(self, rhs: i32) -> Self::Output150     fn add(self, rhs: i32) -> Self::Output {
151         LineId::new(self.0 + rhs)
152     }
153 }
154 impl Sub<i32> for LineId {
155     type Output = LineId;
156 
sub(self, rhs: i32) -> Self::Output157     fn sub(self, rhs: i32) -> Self::Output {
158         LineId::new(self.0 - rhs)
159     }
160 }
161 impl From<LineId> for i32 {
from(value: LineId) -> Self162     fn from(value: LineId) -> Self {
163         value.0
164     }
165 }
166 impl From<LineId> for u32 {
from(value: LineId) -> Self167     fn from(value: LineId) -> Self {
168         value.0 as u32
169     }
170 }
171 impl From<LineId> for usize {
from(value: LineId) -> Self172     fn from(value: LineId) -> Self {
173         value.0 as usize
174     }
175 }
176 impl Sub<LineId> for LineId {
177     type Output = LineId;
178 
sub(mut self, rhs: LineId) -> Self::Output179     fn sub(mut self, rhs: LineId) -> Self::Output {
180         self.0 -= rhs.0;
181         return self;
182     }
183 }
184 impl AddAssign<LineId> for LineId {
add_assign(&mut self, rhs: LineId)185     fn add_assign(&mut self, rhs: LineId) {
186         self.0 += rhs.0;
187     }
188 }
189 #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Default)]
190 pub struct LineIndex(i32);
191 impl LineIndex {
new(num: i32) -> Self192     pub fn new(num: i32) -> Self {
193         LineIndex(num)
194     }
check(&self, chars_per_line: i32) -> bool195     pub fn check(&self, chars_per_line: i32) -> bool {
196         self.0 < chars_per_line && self.0 >= 0
197     }
198 }
199 impl Add<LineIndex> for LineIndex {
200     type Output = LineIndex;
201 
add(self, rhs: LineIndex) -> Self::Output202     fn add(self, rhs: LineIndex) -> Self::Output {
203         LineIndex::new(self.0 + rhs.0)
204     }
205 }
206 impl Add<i32> for LineIndex {
207     // type Output = Self;
208     type Output = LineIndex;
209 
add(self, rhs: i32) -> Self::Output210     fn add(self, rhs: i32) -> Self::Output {
211         LineIndex::new(self.0 + rhs)
212     }
213 }
214 impl Sub<i32> for LineIndex {
215     type Output = LineIndex;
216 
sub(self, rhs: i32) -> Self::Output217     fn sub(self, rhs: i32) -> Self::Output {
218         LineIndex::new(self.0 - rhs)
219     }
220 }
221 
222 impl From<LineIndex> for i32 {
from(val: LineIndex) -> Self223     fn from(val: LineIndex) -> Self {
224         val.0
225     }
226 }
227 impl From<LineIndex> for u32 {
from(value: LineIndex) -> Self228     fn from(value: LineIndex) -> Self {
229         value.0 as u32
230     }
231 }
232 impl From<LineIndex> for usize {
from(value: LineIndex) -> Self233     fn from(value: LineIndex) -> Self {
234         value.0 as usize
235     }
236 }
237 #[derive(Copy, Clone, Debug)]
238 pub struct FontColor(u32);
239 #[allow(dead_code)]
240 impl FontColor {
241     pub const BLUE: FontColor = FontColor::new(0, 0, 0xff);
242     pub const RED: FontColor = FontColor::new(0xff, 0, 0);
243     pub const GREEN: FontColor = FontColor::new(0, 0xff, 0);
244     pub const WHITE: FontColor = FontColor::new(0xff, 0xff, 0xff);
245     pub const BLACK: FontColor = FontColor::new(0, 0, 0);
246     pub const YELLOW: FontColor = FontColor::new(0xff, 0xff, 0);
247     pub const ORANGE: FontColor = FontColor::new(0xff, 0x80, 0);
248     pub const INDIGO: FontColor = FontColor::new(0x00, 0xff, 0xff);
249     pub const PURPLE: FontColor = FontColor::new(0x80, 0x00, 0xff);
250 
new(r: u8, g: u8, b: u8) -> Self251     pub const fn new(r: u8, g: u8, b: u8) -> Self {
252         let val = ((r as u32) << 16) | ((g as u32) << 8) | (b as u32);
253         return FontColor(val & 0x00ffffff);
254     }
255 }
256 
257 impl From<u32> for FontColor {
from(value: u32) -> Self258     fn from(value: u32) -> Self {
259         return Self(value & 0x00ffffff);
260     }
261 }
262 impl From<FontColor> for usize {
from(value: FontColor) -> Self263     fn from(value: FontColor) -> Self {
264         value.0 as usize
265     }
266 }
267 impl From<FontColor> for u32 {
from(value: FontColor) -> Self268     fn from(value: FontColor) -> Self {
269         value.0
270     }
271 }
272 impl From<FontColor> for u16 {
from(value: FontColor) -> Self273     fn from(value: FontColor) -> Self {
274         value.0 as u16
275     }
276 }
277 impl From<FontColor> for u64 {
from(value: FontColor) -> Self278     fn from(value: FontColor) -> Self {
279         value.0 as u64
280     }
281 }
282 
283 /// 彩色字符对象
284 
285 #[derive(Clone, Debug, Copy)]
286 pub struct TextuiCharChromatic {
287     c: Option<char>,
288 
289     // 前景色
290     frcolor: FontColor, // rgb
291 
292     // 背景色
293     bkcolor: FontColor, // rgb
294 }
295 
296 #[derive(Debug)]
297 pub struct TextuiBuf<'a> {
298     buf: Option<&'a mut [u8]>,
299 
300     guard: Option<SpinLockGuard<'a, Box<[u8]>>>,
301 
302     bit_depth: u32,
303 }
304 
305 impl TextuiBuf<'_> {
new(buf: &mut ScmBufferInfo) -> TextuiBuf306     pub fn new(buf: &mut ScmBufferInfo) -> TextuiBuf {
307         let len = buf.buf_size() / 4;
308         let depth = video_refresh_manager().device_buffer().bit_depth();
309         match &buf.buf {
310             ScmBuffer::DeviceBuffer(vaddr) => {
311                 return TextuiBuf {
312                     buf: Some(unsafe {
313                         core::slice::from_raw_parts_mut(vaddr.data() as *mut u8, len)
314                     }),
315                     guard: None,
316                     bit_depth: depth,
317                 };
318             }
319 
320             ScmBuffer::DoubleBuffer(double_buffer) => {
321                 let guard: SpinLockGuard<'_, Box<[u8]>> = double_buffer.lock();
322 
323                 return TextuiBuf {
324                     buf: None,
325                     guard: Some(guard),
326                     bit_depth: depth,
327                 };
328             }
329         }
330     }
331 
buf_mut(&mut self) -> &mut [u8]332     pub fn buf_mut(&mut self) -> &mut [u8] {
333         if let Some(buf) = &mut self.buf {
334             return buf;
335         } else {
336             return self.guard.as_mut().unwrap().as_mut();
337         }
338     }
339 
put_color_in_pixel(&mut self, color: u32, index: usize)340     pub fn put_color_in_pixel(&mut self, color: u32, index: usize) {
341         let index = index as isize;
342         match self.bit_depth {
343             32 => {
344                 let buf = self.buf_mut().as_mut_ptr() as *mut u32;
345                 unsafe {
346                     *buf.offset(index) = color;
347                 }
348             }
349             24 => {
350                 let buf = self.buf_mut().as_mut_ptr();
351                 unsafe {
352                     copy_nonoverlapping(&color as *const u32 as *const u8, buf.offset(index * 3), 3)
353                 };
354             }
355             16 => {
356                 let buf = self.buf_mut().as_mut_ptr();
357                 unsafe {
358                     copy_nonoverlapping(
359                         &color as *const u32 as *const u8,
360                         buf.offset(index * 2),
361                         2,
362                     );
363                 };
364             }
365             _ => {
366                 panic!("bidepth unsupported!")
367             }
368         }
369     }
get_index_of_next_line(now_index: usize) -> usize370     pub fn get_index_of_next_line(now_index: usize) -> usize {
371         textui_framework().metadata.read().buf_info().width() as usize + now_index
372     }
get_index_by_x_y(x: usize, y: usize) -> usize373     pub fn get_index_by_x_y(x: usize, y: usize) -> usize {
374         textui_framework().metadata.read().buf_info().width() as usize * y + x
375     }
376 
get_start_index_by_lineid_lineindex(lineid: LineId, lineindex: LineIndex) -> usize377     pub fn get_start_index_by_lineid_lineindex(lineid: LineId, lineindex: LineIndex) -> usize {
378         //   x 左上角列像素点位置
379         //   y 左上角行像素点位置
380         let index_x: u32 = lineindex.into();
381         let x: u32 = index_x * TEXTUI_CHAR_WIDTH;
382 
383         let id_y: u32 = lineid.into();
384         let y: u32 = id_y * TEXTUI_CHAR_HEIGHT;
385 
386         TextuiBuf::get_index_by_x_y(x as usize, y as usize)
387     }
388 }
389 
390 #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
391 pub struct Font([u8; 16]);
392 impl Font {
393     #[inline]
get_font(character: char) -> Font394     pub fn get_font(character: char) -> Font {
395         let x = FONT_8x16.char_map(character);
396 
397         let mut data = [0u8; 16];
398         data.copy_from_slice(x);
399         return Font(data);
400     }
is_frcolor(&self, height: usize, width: usize) -> bool401     pub fn is_frcolor(&self, height: usize, width: usize) -> bool {
402         let w = self.0[height];
403         let testbit = 1 << (8 - width);
404         w & testbit != 0
405     }
406 }
407 
408 impl TextuiCharChromatic {
new(c: Option<char>, frcolor: FontColor, bkcolor: FontColor) -> Self409     pub fn new(c: Option<char>, frcolor: FontColor, bkcolor: FontColor) -> Self {
410         TextuiCharChromatic {
411             c,
412             frcolor,
413             bkcolor,
414         }
415     }
416 
417     /// 将该字符对象输出到缓冲区
418     /// ## 参数
419     /// -line_id 要放入的真实行号
420     /// -index 要放入的真实列号
textui_refresh_character( &self, lineid: LineId, lineindex: LineIndex, ) -> Result<i32, SystemError>421     pub fn textui_refresh_character(
422         &self,
423         lineid: LineId,
424         lineindex: LineIndex,
425     ) -> Result<i32, SystemError> {
426         // 找到要渲染的字符的像素点数据
427 
428         let font: Font = Font::get_font(self.c.unwrap_or(' '));
429 
430         let mut count = TextuiBuf::get_start_index_by_lineid_lineindex(lineid, lineindex);
431 
432         let mut _binding = textui_framework().metadata.read().buf_info();
433 
434         let mut buf = TextuiBuf::new(&mut _binding);
435 
436         // 在缓冲区画出一个字体,每个字体有TEXTUI_CHAR_HEIGHT行,TEXTUI_CHAR_WIDTH列个像素点
437         for i in 0..TEXTUI_CHAR_HEIGHT {
438             let start = count;
439             for j in 0..TEXTUI_CHAR_WIDTH {
440                 if font.is_frcolor(i as usize, j as usize) {
441                     // 字,显示前景色
442                     buf.put_color_in_pixel(self.frcolor.into(), count);
443                 } else {
444                     // 背景色
445                     buf.put_color_in_pixel(self.bkcolor.into(), count);
446                 }
447                 count += 1;
448             }
449             count = TextuiBuf::get_index_of_next_line(start);
450         }
451 
452         return Ok(0);
453     }
454 
no_init_textui_render_chromatic(&self, lineid: LineId, lineindex: LineIndex)455     pub fn no_init_textui_render_chromatic(&self, lineid: LineId, lineindex: LineIndex) {
456         // 找到要渲染的字符的像素点数据
457         let font = Font::get_font(self.c.unwrap_or(' '));
458 
459         //   x 左上角列像素点位置
460         //   y 左上角行像素点位置
461         let index_x: u32 = lineindex.into();
462         let x: u32 = index_x * TEXTUI_CHAR_WIDTH;
463 
464         let id_y: u32 = lineid.into();
465         let y: u32 = id_y * TEXTUI_CHAR_HEIGHT;
466         let buf_depth = video_refresh_manager().device_buffer().bit_depth();
467         let buf_width = video_refresh_manager().device_buffer().width();
468         let byte_num_of_depth = (buf_depth / 8) as usize;
469 
470         // 找到输入缓冲区的起始地址位置
471         let buf_start =
472             if let ScmBuffer::DeviceBuffer(vaddr) = video_refresh_manager().device_buffer().buf {
473                 vaddr
474             } else {
475                 panic!("device buffer is not init");
476             };
477 
478         let mut testbit: u32; // 用来测试特定行的某列是背景还是字体本身
479 
480         // 在缓冲区画出一个字体,每个字体有TEXTUI_CHAR_HEIGHT行,TEXTUI_CHAR_WIDTH列个像素点
481         for i in 0..TEXTUI_CHAR_HEIGHT {
482             // 计算出帧缓冲区每一行打印的起始位置的地址(起始位置+(y+i)*缓冲区的宽度+x)
483 
484             let mut addr: *mut u8 = (buf_start
485                 + buf_width as usize * byte_num_of_depth * (y as usize + i as usize)
486                 + byte_num_of_depth * x as usize)
487                 .data() as *mut u8;
488 
489             testbit = 1 << (TEXTUI_CHAR_WIDTH + 1);
490 
491             for _j in 0..TEXTUI_CHAR_WIDTH {
492                 //该循环是渲染一行像素
493                 //从左往右逐个测试相应位
494                 testbit >>= 1;
495                 if (font.0[i as usize] & testbit as u8) != 0 {
496                     let color: u32 = self.frcolor.into();
497                     unsafe {
498                         copy_nonoverlapping(
499                             &color as *const u32 as *const u8,
500                             addr,
501                             byte_num_of_depth,
502                         )
503                     }; // 字,显示前景色
504                 } else {
505                     let color: u32 = self.bkcolor.into();
506                     unsafe {
507                         copy_nonoverlapping(
508                             &color as *const u32 as *const u8,
509                             addr,
510                             byte_num_of_depth,
511                         )
512                     };
513                 }
514                 unsafe {
515                     addr = addr.add(byte_num_of_depth);
516                 }
517             }
518         }
519     }
520 }
521 
522 /// 单色显示的虚拟行结构体
523 
524 #[derive(Clone, Debug, Default)]
525 pub struct TextuiVlineNormal {
526     _characters: Vec<TextuiCharNormal>, // 字符对象数组
527     _index: i16,                        // 当前操作的位置
528 }
529 /// 彩色显示的虚拟行结构体
530 
531 #[derive(Clone, Debug, Default)]
532 pub struct TextuiVlineChromatic {
533     chars: Vec<TextuiCharChromatic>, // 字符对象数组
534     index: LineIndex,                // 当前操作的位置
535 }
536 impl TextuiVlineChromatic {
new(char_num: usize) -> Self537     pub fn new(char_num: usize) -> Self {
538         let mut r = TextuiVlineChromatic {
539             chars: Vec::with_capacity(char_num),
540             index: LineIndex::new(0),
541         };
542 
543         for _ in 0..char_num {
544             r.chars.push(TextuiCharChromatic::new(
545                 None,
546                 FontColor::BLACK,
547                 FontColor::BLACK,
548             ));
549         }
550 
551         return r;
552     }
553 }
554 
555 #[derive(Clone, Debug)]
556 pub enum TextuiVline {
557     Chromatic(TextuiVlineChromatic),
558     _Normal(TextuiVlineNormal),
559 }
560 
561 #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
562 pub struct WindowId(u32);
563 
564 impl WindowId {
new() -> Self565     pub fn new() -> Self {
566         static MAX_ID: AtomicU32 = AtomicU32::new(0);
567         return WindowId(MAX_ID.fetch_add(1, Ordering::SeqCst));
568     }
569 }
570 #[allow(dead_code)]
571 #[derive(Clone, Debug)]
572 pub struct TextuiWindow {
573     // 虚拟行是个循环表,头和尾相接
574     id: WindowId,
575     // 虚拟行总数
576     vline_sum: i32,
577     // 当前已经使用了的虚拟行总数(即在已经输入到缓冲区(之后显示在屏幕上)的虚拟行数量)
578     vlines_used: i32,
579     // 位于最顶上的那一个虚拟行的行号
580     top_vline: LineId,
581     // 储存虚拟行的数组
582     vlines: Vec<TextuiVline>,
583     // 正在操作的vline
584     vline_operating: LineId,
585     // 每行最大容纳的字符数
586     chars_per_line: i32,
587     // 窗口flag
588     flags: WindowFlag,
589 }
590 
591 impl TextuiWindow {
592     /// 使用参数初始化window对象
593     /// ## 参数
594     ///
595     /// -flags 标志位
596     /// -vlines_num 虚拟行的总数
597     /// -chars_num 每行最大的字符数
598 
new(flags: WindowFlag, vlines_num: i32, chars_num: i32) -> Self599     pub fn new(flags: WindowFlag, vlines_num: i32, chars_num: i32) -> Self {
600         let mut initial_vlines = Vec::new();
601 
602         for _ in 0..vlines_num {
603             let vline = TextuiVlineChromatic::new(chars_num as usize);
604 
605             initial_vlines.push(TextuiVline::Chromatic(vline));
606         }
607         TextuiWindow {
608             id: WindowId::new(),
609             flags,
610             vline_sum: vlines_num,
611             vlines_used: 1,
612             top_vline: LineId::new(0),
613             vlines: initial_vlines,
614             vline_operating: LineId::new(0),
615             chars_per_line: chars_num,
616         }
617     }
618 
619     /// 刷新某个窗口的缓冲区的某个虚拟行的连续n个字符对象
620     /// ## 参数
621     /// - window 窗口结构体
622     /// - vline_id 要刷新的虚拟行号
623     /// - start 起始字符号
624     /// - count 要刷新的字符数量
textui_refresh_characters( &mut self, vline_id: LineId, start: LineIndex, count: i32, ) -> Result<(), SystemError>625     fn textui_refresh_characters(
626         &mut self,
627         vline_id: LineId,
628         start: LineIndex,
629         count: i32,
630     ) -> Result<(), SystemError> {
631         let actual_line_sum = textui_framework().actual_line.load(Ordering::SeqCst);
632 
633         // 判断虚拟行参数是否合法
634         if unlikely(
635             !vline_id.check(self.vline_sum)
636                 || (<LineIndex as Into<i32>>::into(start) + count) > self.chars_per_line,
637         ) {
638             return Err(SystemError::EINVAL);
639         }
640         // 计算虚拟行对应的真实行(即要渲染的行)
641         let mut actual_line_id = vline_id - self.top_vline; //为正说明虚拟行不在真实行显示的区域上面
642 
643         if <LineId as Into<i32>>::into(actual_line_id) < 0 {
644             //真实行数小于虚拟行数,则需要加上真实行数的位置,以便正确计算真实行
645             actual_line_id = actual_line_id + actual_line_sum;
646         }
647 
648         // 将此窗口的某个虚拟行的连续n个字符对象往缓存区写入
649         if self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) {
650             let vline = &mut self.vlines[<LineId as Into<usize>>::into(vline_id)];
651             let mut i = 0;
652             let mut index = start;
653 
654             while i < count {
655                 if let TextuiVline::Chromatic(vline) = vline {
656                     vline.chars[<LineIndex as Into<usize>>::into(index)]
657                         .textui_refresh_character(actual_line_id, index)?;
658 
659                     index = index + 1;
660                 }
661                 i += 1;
662             }
663         }
664 
665         return Ok(());
666     }
667 
668     /// 重新渲染某个窗口的某个虚拟行
669     /// ## 参数
670 
671     /// - window 窗口结构体
672     /// - vline_id 虚拟行号
673 
textui_refresh_vline(&mut self, vline_id: LineId) -> Result<(), SystemError>674     fn textui_refresh_vline(&mut self, vline_id: LineId) -> Result<(), SystemError> {
675         if self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) {
676             return self.textui_refresh_characters(
677                 vline_id,
678                 LineIndex::new(0),
679                 self.chars_per_line,
680             );
681         } else {
682             //todo支持纯文本字符()
683             todo!();
684         }
685     }
686 
687     // 刷新某个窗口的start 到start + count行(即将这些行输入到缓冲区)
textui_refresh_vlines(&mut self, start: LineId, count: i32) -> Result<i32, SystemError>688     fn textui_refresh_vlines(&mut self, start: LineId, count: i32) -> Result<i32, SystemError> {
689         let mut refresh_count = count;
690         for i in <LineId as Into<i32>>::into(start)
691             ..(self.vline_sum).min(<LineId as Into<i32>>::into(start) + count)
692         {
693             self.textui_refresh_vline(LineId::new(i))?;
694             refresh_count -= 1;
695         }
696         //因为虚拟行是循环表
697         let mut refresh_start = 0;
698         while refresh_count > 0 {
699             self.textui_refresh_vline(LineId::new(refresh_start))?;
700             refresh_start += 1;
701             refresh_count -= 1;
702         }
703         return Ok(0);
704     }
705 
706     /// 往某个窗口的缓冲区的某个虚拟行插入换行
707     /// ## 参数
708     /// - window 窗口结构体
709     /// - vline_id 虚拟行号
textui_new_line(&mut self) -> Result<i32, SystemError>710     fn textui_new_line(&mut self) -> Result<i32, SystemError> {
711         // todo: 支持在两个虚拟行之间插入一个新行
712         let actual_line_sum = textui_framework().actual_line.load(Ordering::SeqCst);
713         self.vline_operating = self.vline_operating + 1;
714         //如果已经到了最大行数,则重新从0开始
715         if !self.vline_operating.check(self.vline_sum) {
716             self.vline_operating = LineId::new(0);
717         }
718 
719         if let TextuiVline::Chromatic(vline) =
720             &mut (self.vlines[<LineId as Into<usize>>::into(self.vline_operating)])
721         {
722             for i in 0..self.chars_per_line {
723                 if let Some(v_char) = vline.chars.get_mut(i as usize) {
724                     v_char.c = None;
725                     v_char.frcolor = FontColor::BLACK;
726                     v_char.bkcolor = FontColor::BLACK;
727                 }
728             }
729             vline.index = LineIndex::new(0);
730         }
731         // 当已经使用的虚拟行总数等于真实行总数时,说明窗口中已经显示的文本行数已经达到了窗口的最大容量。这时,如果继续在窗口中添加新的文本,就会导致文本溢出窗口而无法显示。因此,需要往下滚动屏幕来显示更多的文本。
732 
733         if self.vlines_used == actual_line_sum {
734             self.top_vline = self.top_vline + 1;
735 
736             if !self.top_vline.check(self.vline_sum) {
737                 self.top_vline = LineId::new(0);
738             }
739 
740             // 刷新所有行
741             self.textui_refresh_vlines(self.top_vline, actual_line_sum)?;
742         } else {
743             //换行说明上一行已经在缓冲区中,所以已经使用的虚拟行总数+1
744             self.vlines_used += 1;
745         }
746 
747         return Ok(0);
748     }
749 
750     /// 真正向窗口的缓冲区上输入字符的函数(位置为window.vline_operating,window.vline_operating.index)
751     /// ## 参数
752     /// - window
753     /// - character
true_textui_putchar_window( &mut self, character: char, frcolor: FontColor, bkcolor: FontColor, ) -> Result<(), SystemError>754     fn true_textui_putchar_window(
755         &mut self,
756         character: char,
757         frcolor: FontColor,
758         bkcolor: FontColor,
759     ) -> Result<(), SystemError> {
760         // 启用彩色字符
761         if self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) {
762             let mut line_index = LineIndex::new(0); //操作的列号
763             if let TextuiVline::Chromatic(vline) =
764                 &mut (self.vlines[<LineId as Into<usize>>::into(self.vline_operating)])
765             {
766                 let index = <LineIndex as Into<usize>>::into(vline.index);
767 
768                 if let Some(v_char) = vline.chars.get_mut(index) {
769                     v_char.c = Some(character);
770                     v_char.frcolor = frcolor;
771                     v_char.bkcolor = bkcolor;
772                 }
773                 line_index = vline.index;
774                 vline.index = vline.index + 1;
775             }
776 
777             self.textui_refresh_characters(self.vline_operating, line_index, 1)?;
778 
779             // 加入光标后,因为会识别光标,所以需超过该行最大字符数才能创建新行
780             if !line_index.check(self.chars_per_line - 1) {
781                 self.textui_new_line()?;
782             }
783         } else {
784             // todo: 支持纯文本字符
785             todo!();
786         }
787         return Ok(());
788     }
789     /// 根据输入的一个字符在窗口上输出
790     /// ## 参数
791 
792     /// - window 窗口
793     /// - character 字符
794     /// - FRcolor 前景色(RGB)
795     /// - BKcolor 背景色(RGB)
796 
textui_putchar_window( &mut self, character: char, frcolor: FontColor, bkcolor: FontColor, is_enable_window: bool, ) -> Result<(), SystemError>797     fn textui_putchar_window(
798         &mut self,
799         character: char,
800         frcolor: FontColor,
801         bkcolor: FontColor,
802         is_enable_window: bool,
803     ) -> Result<(), SystemError> {
804         let actual_line_sum = textui_framework().actual_line.load(Ordering::SeqCst);
805 
806         //字符'\0'代表ASCII码表中的空字符,表示字符串的结尾
807         if unlikely(character == '\0') {
808             return Ok(());
809         }
810 
811         if unlikely(character == '\r') {
812             return Ok(());
813         }
814 
815         // 暂不支持纯文本窗口
816         if !self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) {
817             return Ok(());
818         }
819         send_to_default_serial8250_port(&[character as u8]);
820 
821         //进行换行操作
822         if character == '\n' {
823             // 换行时还需要输出\r
824             send_to_default_serial8250_port(b"\r");
825             if is_enable_window {
826                 self.textui_new_line()?;
827             }
828             return Ok(());
829         }
830         // 输出制表符
831         else if character == '\t' {
832             if is_enable_window {
833                 if let TextuiVline::Chromatic(vline) =
834                     &self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
835                 {
836                     //打印的空格数(注意将每行分成一个个表格,每个表格为8个字符)
837                     let mut space_to_print = 8 - <LineIndex as Into<usize>>::into(vline.index) % 8;
838                     while space_to_print > 0 {
839                         self.true_textui_putchar_window(' ', frcolor, bkcolor)?;
840                         space_to_print -= 1;
841                     }
842                 }
843             }
844         }
845         // 字符 '\x08' 代表 ASCII 码中的退格字符。它在输出中的作用是将光标向左移动一个位置,并在该位置上输出后续的字符,从而实现字符的删除或替换。
846         else if character == '\x08' {
847             if is_enable_window {
848                 let mut tmp = LineIndex(0);
849                 if let TextuiVline::Chromatic(vline) =
850                     &mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
851                 {
852                     vline.index = vline.index - 1;
853                     tmp = vline.index;
854                 }
855                 if <LineIndex as Into<i32>>::into(tmp) >= 0 {
856                     if let TextuiVline::Chromatic(vline) =
857                         &mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
858                     {
859                         if let Some(v_char) =
860                             vline.chars.get_mut(<LineIndex as Into<usize>>::into(tmp))
861                         {
862                             v_char.c = Some(' ');
863 
864                             v_char.bkcolor = bkcolor;
865                         }
866                     }
867                     return self.textui_refresh_characters(self.vline_operating, tmp, 1);
868                 }
869                 // 需要向上缩一行
870                 if <LineIndex as Into<i32>>::into(tmp) < 0 {
871                     // 当前行为空,需要重新刷新
872                     if let TextuiVline::Chromatic(vline) =
873                         &mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
874                     {
875                         vline.index = LineIndex::new(0);
876                         for i in 0..self.chars_per_line {
877                             if let Some(v_char) = vline.chars.get_mut(i as usize) {
878                                 v_char.c = None;
879                                 v_char.frcolor = FontColor::BLACK;
880                                 v_char.bkcolor = FontColor::BLACK;
881                             }
882                         }
883                     }
884                     // 上缩一行
885                     self.vline_operating = self.vline_operating - 1;
886                     if self.vline_operating.data() < 0 {
887                         self.vline_operating = LineId(self.vline_sum - 1);
888                     }
889 
890                     // 考虑是否向上滚动(在top_vline上退格)
891                     if self.vlines_used > actual_line_sum {
892                         self.top_vline = self.top_vline - 1;
893                         if <LineId as Into<i32>>::into(self.top_vline) < 0 {
894                             self.top_vline = LineId(self.vline_sum - 1);
895                         }
896                     }
897                     //因为上缩一行所以显示在屏幕中的虚拟行少一
898                     self.vlines_used -= 1;
899                     self.textui_refresh_vlines(self.top_vline, actual_line_sum)?;
900                 }
901             }
902         } else if is_enable_window {
903             if let TextuiVline::Chromatic(vline) =
904                 &self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
905             {
906                 if !vline.index.check(self.chars_per_line) {
907                     self.textui_new_line()?;
908                 }
909 
910                 return self.true_textui_putchar_window(character, frcolor, bkcolor);
911             }
912         }
913 
914         return Ok(());
915     }
916 }
917 impl Default for TextuiWindow {
default() -> Self918     fn default() -> Self {
919         TextuiWindow {
920             id: WindowId(0),
921             flags: WindowFlag::TEXTUI_CHROMATIC,
922             vline_sum: 0,
923             vlines_used: 1,
924             top_vline: LineId::new(0),
925             vlines: Vec::new(),
926             vline_operating: LineId::new(0),
927             chars_per_line: 0,
928         }
929     }
930 }
931 #[allow(dead_code)]
932 #[derive(Debug)]
933 pub struct TextUiFramework {
934     metadata: RwLock<ScmUiFrameworkMetadata>,
935     window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>>,
936     actual_line: AtomicI32, // 真实行的数量(textui的帧缓冲区能容纳的内容的行数)
937     current_window: Arc<SpinLock<TextuiWindow>>, // 当前的主窗口
938     default_window: Arc<SpinLock<TextuiWindow>>, // 默认print到的窗口
939 }
940 
941 impl TextUiFramework {
new( metadata: ScmUiFrameworkMetadata, window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>>, current_window: Arc<SpinLock<TextuiWindow>>, default_window: Arc<SpinLock<TextuiWindow>>, ) -> Self942     pub fn new(
943         metadata: ScmUiFrameworkMetadata,
944         window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>>,
945         current_window: Arc<SpinLock<TextuiWindow>>,
946         default_window: Arc<SpinLock<TextuiWindow>>,
947     ) -> Self {
948         let actual_line =
949             AtomicI32::new((metadata.buf_info().height() / TEXTUI_CHAR_HEIGHT) as i32);
950         let inner = TextUiFramework {
951             metadata: RwLock::new(metadata),
952             window_list,
953             actual_line,
954             current_window,
955             default_window,
956         };
957         return inner;
958     }
959 }
960 
961 impl ScmUiFramework for TextUiFramework {
962     // 安装ui框架的回调函数
install(&self) -> Result<i32, SystemError>963     fn install(&self) -> Result<i32, SystemError> {
964         send_to_default_serial8250_port("\ntextui_install_handler\n\0".as_bytes());
965         return Ok(0);
966     }
967     // 卸载ui框架的回调函数
uninstall(&self) -> Result<i32, SystemError>968     fn uninstall(&self) -> Result<i32, SystemError> {
969         return Ok(0);
970     }
971     // 启用ui框架的回调函数
enable(&self) -> Result<i32, SystemError>972     fn enable(&self) -> Result<i32, SystemError> {
973         textui_enable_put_to_window();
974         return Ok(0);
975     }
976     // 禁用ui框架的回调函数
disable(&self) -> Result<i32, SystemError>977     fn disable(&self) -> Result<i32, SystemError> {
978         textui_disable_put_to_window();
979 
980         return Ok(0);
981     }
982     // 改变ui框架的帧缓冲区的回调函数
change(&self, buf_info: ScmBufferInfo) -> Result<i32, SystemError>983     fn change(&self, buf_info: ScmBufferInfo) -> Result<i32, SystemError> {
984         let old_buf = textui_framework().metadata.read().buf_info();
985 
986         textui_framework().metadata.write().set_buf_info(buf_info);
987 
988         let mut new_buf = textui_framework().metadata.read().buf_info();
989 
990         new_buf.copy_from_nonoverlapping(&old_buf);
991         debug!("textui change buf_info: old: {:?}", old_buf);
992         debug!("textui change buf_info: new: {:?}", new_buf);
993 
994         return Ok(0);
995     }
996     ///  获取ScmUiFramework的元数据
997     ///  ## 返回值
998     ///
999     ///  -成功:Ok(ScmUiFramework的元数据)
1000     ///  -失败:Err(错误码)
metadata(&self) -> Result<ScmUiFrameworkMetadata, SystemError>1001     fn metadata(&self) -> Result<ScmUiFrameworkMetadata, SystemError> {
1002         let metadata = self.metadata.read().clone();
1003 
1004         return Ok(metadata);
1005     }
1006 }
1007 
1008 /// Mapping from characters to glyph indices.
1009 pub trait GlyphMapping: Sync {
1010     /// Maps a character to a glyph index.
1011     ///
1012     /// If `c` isn't included in the font the index of a suitable replacement glyph is returned.
index(&self, c: char) -> usize1013     fn index(&self, c: char) -> usize;
1014 }
1015 
1016 impl<F> GlyphMapping for F
1017 where
1018     F: Sync + Fn(char) -> usize,
1019 {
index(&self, c: char) -> usize1020     fn index(&self, c: char) -> usize {
1021         self(c)
1022     }
1023 }
1024 
1025 /// 在默认窗口上输出一个字符
1026 /// ## 参数
1027 /// - character 字符
1028 /// - FRcolor 前景色(RGB)
1029 /// - BKcolor 背景色(RGB)
1030 
1031 #[no_mangle]
rs_textui_putchar(character: u8, fr_color: u32, bk_color: u32) -> i321032 pub extern "C" fn rs_textui_putchar(character: u8, fr_color: u32, bk_color: u32) -> i32 {
1033     if let Some(current_vc) = vc_manager().current_vc() {
1034         // tty已经初始化了之后才输出到屏幕
1035         let fr = (fr_color & 0x00ff0000) >> 16;
1036         let fg = (fr_color & 0x0000ff00) >> 8;
1037         let fb = fr_color & 0x000000ff;
1038         let br = (bk_color & 0x00ff0000) >> 16;
1039         let bg = (bk_color & 0x0000ff00) >> 8;
1040         let bb = bk_color & 0x000000ff;
1041         let buf = format!(
1042             "\x1B[38;2;{fr};{fg};{fb};48;2;{br};{bg};{bb}m{}\x1B[0m",
1043             character as char
1044         );
1045         let port = current_vc.port();
1046         let tty = port.port_data().internal_tty();
1047         if let Some(tty) = tty {
1048             return tty
1049                 .write_to_core(buf.as_bytes(), buf.len())
1050                 .map(|_| 0)
1051                 .unwrap_or_else(|e| e.to_posix_errno());
1052         }
1053     }
1054     return textui_putchar(
1055         character as char,
1056         FontColor::from(fr_color),
1057         FontColor::from(bk_color),
1058     )
1059     .map(|_| 0)
1060     .unwrap_or_else(|e| e.to_posix_errno());
1061 }
1062 
textui_putchar( character: char, fr_color: FontColor, bk_color: FontColor, ) -> Result<(), SystemError>1063 pub fn textui_putchar(
1064     character: char,
1065     fr_color: FontColor,
1066     bk_color: FontColor,
1067 ) -> Result<(), SystemError> {
1068     if unsafe { TEXTUI_IS_INIT } {
1069         return textui_framework()
1070             .current_window
1071             .lock_irqsave()
1072             .textui_putchar_window(
1073                 character,
1074                 fr_color,
1075                 bk_color,
1076                 textui_is_enable_put_to_window(),
1077             );
1078     } else {
1079         //未初始化暴力输出
1080         return no_init_textui_putchar_window(
1081             character,
1082             fr_color,
1083             bk_color,
1084             textui_is_enable_put_to_window(),
1085         );
1086     }
1087 }
1088 
1089 /// 向默认窗口输出一个字符串
textui_putstr( string: &str, fr_color: FontColor, bk_color: FontColor, ) -> Result<(), SystemError>1090 pub fn textui_putstr(
1091     string: &str,
1092     fr_color: FontColor,
1093     bk_color: FontColor,
1094 ) -> Result<(), SystemError> {
1095     let window = if unsafe { TEXTUI_IS_INIT } {
1096         let fw = textui_framework();
1097         let w = fw.current_window.clone();
1098         Some(w)
1099     } else {
1100         None
1101     };
1102 
1103     let mut guard = window.as_ref().map(|w| w.lock_irqsave());
1104 
1105     for character in string.chars() {
1106         if unsafe { TEXTUI_IS_INIT } {
1107             guard.as_mut().unwrap().textui_putchar_window(
1108                 character,
1109                 fr_color,
1110                 bk_color,
1111                 textui_is_enable_put_to_window(),
1112             )?;
1113         } else {
1114             no_init_textui_putchar_window(
1115                 character,
1116                 fr_color,
1117                 bk_color,
1118                 textui_is_enable_put_to_window(),
1119             )?;
1120         }
1121     }
1122 
1123     return Ok(());
1124 }
1125 
1126 /// 初始化text ui框架
1127 #[inline(never)]
textui_init() -> Result<i32, SystemError>1128 pub fn textui_init() -> Result<i32, SystemError> {
1129     #[cfg(target_arch = "x86_64")]
1130     textui_framwork_init();
1131 
1132     return Ok(0);
1133 }
1134