xref: /DragonOS/kernel/src/driver/video/fbdev/base/fbcon/framebuffer_console.rs (revision 418ad41fd84c15ed7e132e56970150ac38fc24a9)
152da9a59SGnoCiYeH use alloc::{sync::Arc, vec::Vec};
252da9a59SGnoCiYeH use system_error::SystemError;
352da9a59SGnoCiYeH 
452da9a59SGnoCiYeH use crate::{
552da9a59SGnoCiYeH     driver::{
652da9a59SGnoCiYeH         tty::{
752da9a59SGnoCiYeH             console::ConsoleSwitch,
852da9a59SGnoCiYeH             virtual_terminal::{
952da9a59SGnoCiYeH                 virtual_console::{CursorOperation, ScrollDir, VcCursor, VirtualConsoleData},
1052da9a59SGnoCiYeH                 Color,
1152da9a59SGnoCiYeH             },
1252da9a59SGnoCiYeH         },
1352da9a59SGnoCiYeH         video::fbdev::base::{
1452da9a59SGnoCiYeH             CopyAreaData, FbCursor, FbCursorSetMode, FbImage, FbVisual, FillRectData, FillRectROP,
1552da9a59SGnoCiYeH             FrameBuffer, ScrollMode, FRAME_BUFFER_SET,
1652da9a59SGnoCiYeH         },
1752da9a59SGnoCiYeH     },
1852da9a59SGnoCiYeH     libs::{
1952da9a59SGnoCiYeH         font::FontDesc,
2052da9a59SGnoCiYeH         spinlock::{SpinLock, SpinLockGuard},
2152da9a59SGnoCiYeH     },
2252da9a59SGnoCiYeH };
2352da9a59SGnoCiYeH 
2452da9a59SGnoCiYeH use super::{FbConAttr, FrameBufferConsole, FrameBufferConsoleData};
2552da9a59SGnoCiYeH 
2652da9a59SGnoCiYeH #[derive(Debug)]
2752da9a59SGnoCiYeH pub struct BlittingFbConsole {
2852da9a59SGnoCiYeH     fb: SpinLock<Option<Arc<dyn FrameBuffer>>>,
2952da9a59SGnoCiYeH     fbcon_data: SpinLock<FrameBufferConsoleData>,
3052da9a59SGnoCiYeH }
3152da9a59SGnoCiYeH 
3252da9a59SGnoCiYeH unsafe impl Send for BlittingFbConsole {}
3352da9a59SGnoCiYeH unsafe impl Sync for BlittingFbConsole {}
3452da9a59SGnoCiYeH 
3552da9a59SGnoCiYeH impl BlittingFbConsole {
3652da9a59SGnoCiYeH     pub fn new() -> Result<Self, SystemError> {
3752da9a59SGnoCiYeH         Ok(Self {
3852da9a59SGnoCiYeH             fb: SpinLock::new(None),
3952da9a59SGnoCiYeH             fbcon_data: SpinLock::new(FrameBufferConsoleData::default()),
4052da9a59SGnoCiYeH         })
4152da9a59SGnoCiYeH     }
4252da9a59SGnoCiYeH 
43*418ad41fSLoGin     fn fb(&self) -> Arc<dyn FrameBuffer> {
4452da9a59SGnoCiYeH         self.fb.lock().clone().unwrap()
4552da9a59SGnoCiYeH     }
4652da9a59SGnoCiYeH 
47*418ad41fSLoGin     fn get_color(&self, vc_data: &VirtualConsoleData, c: u16, is_fg: bool) -> u32 {
4852da9a59SGnoCiYeH         let fb_info = self.fb();
4952da9a59SGnoCiYeH         let mut color = 0;
5052da9a59SGnoCiYeH 
5152da9a59SGnoCiYeH         let depth = fb_info.color_depth();
5252da9a59SGnoCiYeH 
5352da9a59SGnoCiYeH         if depth != 1 {
5452da9a59SGnoCiYeH             if is_fg {
5552da9a59SGnoCiYeH                 let fg_shift = if vc_data.hi_font_mask != 0 { 9 } else { 8 };
5652da9a59SGnoCiYeH                 color = (c as u32 >> fg_shift) & 0x0f
5752da9a59SGnoCiYeH             } else {
5852da9a59SGnoCiYeH                 let bg_shift = if vc_data.hi_font_mask != 0 { 13 } else { 12 };
5952da9a59SGnoCiYeH                 color = (c as u32 >> bg_shift) & 0x0f
6052da9a59SGnoCiYeH             }
6152da9a59SGnoCiYeH         }
6252da9a59SGnoCiYeH 
6352da9a59SGnoCiYeH         match depth {
6452da9a59SGnoCiYeH             1 => {
6552da9a59SGnoCiYeH                 let col = self.mono_color();
6652da9a59SGnoCiYeH                 let fg;
6752da9a59SGnoCiYeH                 let bg;
6852da9a59SGnoCiYeH                 if fb_info.current_fb_fix().visual != FbVisual::Mono01 {
6952da9a59SGnoCiYeH                     fg = col;
7052da9a59SGnoCiYeH                     bg = 0;
7152da9a59SGnoCiYeH                 } else {
7252da9a59SGnoCiYeH                     fg = 0;
7352da9a59SGnoCiYeH                     bg = col;
7452da9a59SGnoCiYeH                 }
7552da9a59SGnoCiYeH                 color = if is_fg { fg } else { bg };
7652da9a59SGnoCiYeH             }
7752da9a59SGnoCiYeH             2 => {
7852da9a59SGnoCiYeH                 /*
7952da9a59SGnoCiYeH                     颜色深度为2,即16色,
8052da9a59SGnoCiYeH                    将16色的颜色值映射到4色的灰度,
8152da9a59SGnoCiYeH                    其中颜色0映射为黑色,颜色1到6映射为白色,
8252da9a59SGnoCiYeH                    颜色7到8映射为灰色,其他颜色映射为强烈的白色。
8352da9a59SGnoCiYeH                 */
84b5b571e0SLoGin                 if (1..=6).contains(&color) {
8552da9a59SGnoCiYeH                     // 白色
8652da9a59SGnoCiYeH                     color = 2;
87b5b571e0SLoGin                 } else if (7..=8).contains(&color) {
8852da9a59SGnoCiYeH                     // 灰色
8952da9a59SGnoCiYeH                     color = 1;
9052da9a59SGnoCiYeH                 } else {
9152da9a59SGnoCiYeH                     // 强白
9252da9a59SGnoCiYeH                     color = 3;
9352da9a59SGnoCiYeH                 }
9452da9a59SGnoCiYeH             }
9552da9a59SGnoCiYeH             3 => {
9652da9a59SGnoCiYeH                 /*
9752da9a59SGnoCiYeH                    颜色深度为3,即256色,仅保留颜色的低3位,即颜色 0 到 7
9852da9a59SGnoCiYeH                 */
9952da9a59SGnoCiYeH                 color &= 7;
10052da9a59SGnoCiYeH             }
10152da9a59SGnoCiYeH             _ => {}
10252da9a59SGnoCiYeH         }
10352da9a59SGnoCiYeH         color
10452da9a59SGnoCiYeH     }
10552da9a59SGnoCiYeH 
10652da9a59SGnoCiYeH     /// ## 计算单色调的函数
107*418ad41fSLoGin     fn mono_color(&self) -> u32 {
10852da9a59SGnoCiYeH         let fb_info = self.fb();
10952da9a59SGnoCiYeH         let mut max_len = fb_info
11052da9a59SGnoCiYeH             .current_fb_var()
11152da9a59SGnoCiYeH             .green
11252da9a59SGnoCiYeH             .length
11352da9a59SGnoCiYeH             .max(fb_info.current_fb_var().red.length);
11452da9a59SGnoCiYeH 
11552da9a59SGnoCiYeH         max_len = max_len.max(fb_info.current_fb_var().blue.length);
11652da9a59SGnoCiYeH 
11752da9a59SGnoCiYeH         return (!(0xfff << max_len)) & 0xff;
11852da9a59SGnoCiYeH     }
11952da9a59SGnoCiYeH 
120*418ad41fSLoGin     fn bit_put_string(
12152da9a59SGnoCiYeH         &self,
12252da9a59SGnoCiYeH         vc_data: &VirtualConsoleData,
12352da9a59SGnoCiYeH         buf: &[u16],
12452da9a59SGnoCiYeH         attr: FbConAttr,
12552da9a59SGnoCiYeH         cnt: u32,
12652da9a59SGnoCiYeH         cellsize: u32,
12752da9a59SGnoCiYeH         image: &mut FbImage,
12852da9a59SGnoCiYeH     ) {
12952da9a59SGnoCiYeH         let charmask = if vc_data.hi_font_mask != 0 {
13052da9a59SGnoCiYeH             0x1ff
13152da9a59SGnoCiYeH         } else {
13252da9a59SGnoCiYeH             0xff
13352da9a59SGnoCiYeH         };
13452da9a59SGnoCiYeH 
13552da9a59SGnoCiYeH         let mut offset;
13652da9a59SGnoCiYeH         let image_line_byte = image.width as usize / 8;
13752da9a59SGnoCiYeH 
13852da9a59SGnoCiYeH         let byte_width = vc_data.font.width as usize / 8;
13952da9a59SGnoCiYeH         let font_height = vc_data.font.height as usize;
14052da9a59SGnoCiYeH         // let mut char_offset = 0;
141b5b571e0SLoGin         for (char_offset, char_item) in buf.iter().enumerate().take(cnt as usize) {
14252da9a59SGnoCiYeH             // 在字符表中的index
143b5b571e0SLoGin             let ch = char_item & charmask;
14452da9a59SGnoCiYeH             // 计算出在font表中的偏移量
14552da9a59SGnoCiYeH             let font_offset = ch as usize * cellsize as usize;
14652da9a59SGnoCiYeH             let font_offset_end = font_offset + cellsize as usize;
14752da9a59SGnoCiYeH             // 设置image的data
14852da9a59SGnoCiYeH 
14952da9a59SGnoCiYeH             let src = &vc_data.font.data[font_offset..font_offset_end];
150b5b571e0SLoGin             let mut dst = vec![0; src.len()];
15152da9a59SGnoCiYeH             dst.copy_from_slice(src);
15252da9a59SGnoCiYeH 
15352da9a59SGnoCiYeH             if !attr.is_empty() {
15452da9a59SGnoCiYeH                 attr.update_attr(&mut dst, src, vc_data)
15552da9a59SGnoCiYeH             }
15652da9a59SGnoCiYeH 
15752da9a59SGnoCiYeH             offset = char_offset * byte_width;
15852da9a59SGnoCiYeH             let mut dst_offset = 0;
15952da9a59SGnoCiYeH             for _ in 0..font_height {
16052da9a59SGnoCiYeH                 let dst_offset_next = dst_offset + byte_width;
16152da9a59SGnoCiYeH                 image.data[offset..offset + byte_width]
16252da9a59SGnoCiYeH                     .copy_from_slice(&dst[dst_offset..dst_offset_next]);
16352da9a59SGnoCiYeH 
16452da9a59SGnoCiYeH                 offset += image_line_byte;
16552da9a59SGnoCiYeH                 dst_offset = dst_offset_next;
16652da9a59SGnoCiYeH             }
16752da9a59SGnoCiYeH         }
16852da9a59SGnoCiYeH 
16952da9a59SGnoCiYeH         self.fb().fb_image_blit(image);
17052da9a59SGnoCiYeH     }
17152da9a59SGnoCiYeH }
17252da9a59SGnoCiYeH 
17352da9a59SGnoCiYeH impl ConsoleSwitch for BlittingFbConsole {
17452da9a59SGnoCiYeH     fn con_init(
17552da9a59SGnoCiYeH         &self,
17652da9a59SGnoCiYeH         vc_data: &mut VirtualConsoleData,
17752da9a59SGnoCiYeH         init: bool,
17852da9a59SGnoCiYeH     ) -> Result<(), system_error::SystemError> {
17952da9a59SGnoCiYeH         let fb_set_guard = FRAME_BUFFER_SET.read();
18052da9a59SGnoCiYeH         let fb = fb_set_guard.get(vc_data.index);
18152da9a59SGnoCiYeH         if fb.is_none() {
18252da9a59SGnoCiYeH             return Err(SystemError::EINVAL);
18352da9a59SGnoCiYeH         }
18452da9a59SGnoCiYeH         let fb = fb.unwrap();
18552da9a59SGnoCiYeH         if fb.is_none() {
18652da9a59SGnoCiYeH             panic!(
18752da9a59SGnoCiYeH                 "The Framebuffer with FbID {} has not been initialized yet.",
18852da9a59SGnoCiYeH                 vc_data.index
18952da9a59SGnoCiYeH             )
19052da9a59SGnoCiYeH         }
19152da9a59SGnoCiYeH 
19252da9a59SGnoCiYeH         let fb = fb.as_ref().unwrap().clone();
19352da9a59SGnoCiYeH 
19452da9a59SGnoCiYeH         if init {
19552da9a59SGnoCiYeH             // 初始化字体
19652da9a59SGnoCiYeH             let var = fb.current_fb_var();
19752da9a59SGnoCiYeH             let font = FontDesc::get_default_font(var.xres, var.yres, 0, 0);
19852da9a59SGnoCiYeH             vc_data.font.data = font.data.to_vec();
19952da9a59SGnoCiYeH             vc_data.font.width = font.width;
20052da9a59SGnoCiYeH             vc_data.font.height = font.height;
20152da9a59SGnoCiYeH             vc_data.font.count = font.char_count;
20252da9a59SGnoCiYeH         } else {
20352da9a59SGnoCiYeH             kwarn!("The frontend Framebuffer is not implemented");
20452da9a59SGnoCiYeH         }
20552da9a59SGnoCiYeH 
20652da9a59SGnoCiYeH         vc_data.color_mode = fb.color_depth() != 1;
20752da9a59SGnoCiYeH         vc_data.complement_mask = if vc_data.color_mode { 0x7700 } else { 0x0800 };
20852da9a59SGnoCiYeH 
20952da9a59SGnoCiYeH         if vc_data.font.count == 256 {
21052da9a59SGnoCiYeH             // ascii
21152da9a59SGnoCiYeH             vc_data.hi_font_mask = 0;
21252da9a59SGnoCiYeH         } else {
21352da9a59SGnoCiYeH             vc_data.hi_font_mask = 0x100;
21452da9a59SGnoCiYeH             if vc_data.color_mode {
21552da9a59SGnoCiYeH                 vc_data.complement_mask <<= 1;
21652da9a59SGnoCiYeH             }
21752da9a59SGnoCiYeH         }
21852da9a59SGnoCiYeH 
21952da9a59SGnoCiYeH         // TODO: 考虑rotate
22052da9a59SGnoCiYeH         if init {
22152da9a59SGnoCiYeH             vc_data.cols = (fb.current_fb_var().xres / vc_data.font.width) as usize;
22252da9a59SGnoCiYeH             vc_data.rows = (fb.current_fb_var().yres / vc_data.font.height) as usize;
22352da9a59SGnoCiYeH 
22452da9a59SGnoCiYeH             vc_data.pos = vc_data.state.x + vc_data.state.y * vc_data.cols;
22552da9a59SGnoCiYeH 
22652da9a59SGnoCiYeH             let new_size = vc_data.cols * vc_data.rows;
22752da9a59SGnoCiYeH             vc_data.screen_buf.resize(new_size, 0);
22852da9a59SGnoCiYeH         } else {
22952da9a59SGnoCiYeH             unimplemented!("Resize is not supported at the moment!");
23052da9a59SGnoCiYeH         }
23152da9a59SGnoCiYeH 
23252da9a59SGnoCiYeH         // 初始化fb
23352da9a59SGnoCiYeH         *self.fb.lock() = Some(fb);
23452da9a59SGnoCiYeH 
23552da9a59SGnoCiYeH         Ok(())
23652da9a59SGnoCiYeH     }
23752da9a59SGnoCiYeH 
23852da9a59SGnoCiYeH     fn con_deinit(&self) -> Result<(), system_error::SystemError> {
23952da9a59SGnoCiYeH         todo!()
24052da9a59SGnoCiYeH     }
24152da9a59SGnoCiYeH 
24252da9a59SGnoCiYeH     fn con_clear(
24352da9a59SGnoCiYeH         &self,
24452da9a59SGnoCiYeH         vc_data: &mut VirtualConsoleData,
24552da9a59SGnoCiYeH         sy: usize,
24652da9a59SGnoCiYeH         sx: usize,
24752da9a59SGnoCiYeH         height: usize,
24852da9a59SGnoCiYeH         width: usize,
24952da9a59SGnoCiYeH     ) -> Result<(), system_error::SystemError> {
25052da9a59SGnoCiYeH         let fb_data = self.fbcon_data();
25152da9a59SGnoCiYeH 
25252da9a59SGnoCiYeH         if height == 0 || width == 0 {
25352da9a59SGnoCiYeH             return Ok(());
25452da9a59SGnoCiYeH         }
25552da9a59SGnoCiYeH 
25652da9a59SGnoCiYeH         let y_break = (fb_data.display.virt_rows - fb_data.display.yscroll) as usize;
257b5b571e0SLoGin         if sy < y_break && sy + height > y_break {
25852da9a59SGnoCiYeH             // 分两次clear
25952da9a59SGnoCiYeH             let b = y_break - sy;
26052da9a59SGnoCiYeH             let _ = self.clear(
261b5b571e0SLoGin                 vc_data,
26252da9a59SGnoCiYeH                 fb_data.display.real_y(sy as u32),
26352da9a59SGnoCiYeH                 sx as u32,
26452da9a59SGnoCiYeH                 b as u32,
26552da9a59SGnoCiYeH                 width as u32,
26652da9a59SGnoCiYeH             );
26752da9a59SGnoCiYeH             let _ = self.clear(
268b5b571e0SLoGin                 vc_data,
26952da9a59SGnoCiYeH                 fb_data.display.real_y((sy + b) as u32),
27052da9a59SGnoCiYeH                 sx as u32,
27152da9a59SGnoCiYeH                 (height - b) as u32,
27252da9a59SGnoCiYeH                 width as u32,
27352da9a59SGnoCiYeH             );
27452da9a59SGnoCiYeH         } else {
27552da9a59SGnoCiYeH             let _ = self.clear(
276b5b571e0SLoGin                 vc_data,
27752da9a59SGnoCiYeH                 fb_data.display.real_y(sy as u32),
27852da9a59SGnoCiYeH                 sx as u32,
27952da9a59SGnoCiYeH                 height as u32,
28052da9a59SGnoCiYeH                 width as u32,
28152da9a59SGnoCiYeH             );
28252da9a59SGnoCiYeH         }
28352da9a59SGnoCiYeH 
28452da9a59SGnoCiYeH         Ok(())
28552da9a59SGnoCiYeH     }
28652da9a59SGnoCiYeH 
28752da9a59SGnoCiYeH     fn con_putc(
28852da9a59SGnoCiYeH         &self,
28952da9a59SGnoCiYeH         vc_data: &VirtualConsoleData,
29052da9a59SGnoCiYeH         ch: u16,
29152da9a59SGnoCiYeH         xpos: u32,
29252da9a59SGnoCiYeH         ypos: u32,
29352da9a59SGnoCiYeH     ) -> Result<(), system_error::SystemError> {
29452da9a59SGnoCiYeH         self.con_putcs(vc_data, &[ch], 1, ypos, xpos)
29552da9a59SGnoCiYeH     }
29652da9a59SGnoCiYeH 
29752da9a59SGnoCiYeH     fn con_putcs(
29852da9a59SGnoCiYeH         &self,
29952da9a59SGnoCiYeH         vc_data: &VirtualConsoleData,
30052da9a59SGnoCiYeH         buf: &[u16],
30152da9a59SGnoCiYeH         count: usize,
30252da9a59SGnoCiYeH         ypos: u32,
30352da9a59SGnoCiYeH         xpos: u32,
30452da9a59SGnoCiYeH     ) -> Result<(), SystemError> {
30552da9a59SGnoCiYeH         if count == 0 {
30652da9a59SGnoCiYeH             return Ok(());
30752da9a59SGnoCiYeH         }
30852da9a59SGnoCiYeH         let fbcon_data = self.fbcon_data();
30952da9a59SGnoCiYeH         let c = buf[0];
31052da9a59SGnoCiYeH         self.put_string(
31152da9a59SGnoCiYeH             vc_data,
31252da9a59SGnoCiYeH             buf,
31352da9a59SGnoCiYeH             count as u32,
31452da9a59SGnoCiYeH             fbcon_data.display.real_y(ypos),
31552da9a59SGnoCiYeH             xpos,
31652da9a59SGnoCiYeH             self.get_color(vc_data, c, true),
31752da9a59SGnoCiYeH             self.get_color(vc_data, c, false),
31852da9a59SGnoCiYeH         )
31952da9a59SGnoCiYeH     }
32052da9a59SGnoCiYeH 
32152da9a59SGnoCiYeH     fn con_getxy(
32252da9a59SGnoCiYeH         &self,
32352da9a59SGnoCiYeH         vc_data: &VirtualConsoleData,
32452da9a59SGnoCiYeH         pos: usize,
32552da9a59SGnoCiYeH     ) -> Result<(usize, usize, usize), SystemError> {
32652da9a59SGnoCiYeH         if pos < vc_data.screen_buf.len() {
32752da9a59SGnoCiYeH             let x = pos % vc_data.cols;
32852da9a59SGnoCiYeH             let y = pos / vc_data.cols;
32952da9a59SGnoCiYeH             let mut next_line_start = pos + (vc_data.cols - x);
33052da9a59SGnoCiYeH             if next_line_start >= vc_data.screen_buf.len() {
33152da9a59SGnoCiYeH                 next_line_start = 0
33252da9a59SGnoCiYeH             }
33352da9a59SGnoCiYeH             return Ok((next_line_start, x, y));
33452da9a59SGnoCiYeH         } else {
33552da9a59SGnoCiYeH             return Ok((0, 0, 0));
33652da9a59SGnoCiYeH         }
33752da9a59SGnoCiYeH     }
33852da9a59SGnoCiYeH 
339b5b571e0SLoGin     #[allow(clippy::if_same_then_else)]
34052da9a59SGnoCiYeH     fn con_cursor(
34152da9a59SGnoCiYeH         &self,
34252da9a59SGnoCiYeH         vc_data: &VirtualConsoleData,
34352da9a59SGnoCiYeH         op: crate::driver::tty::virtual_terminal::virtual_console::CursorOperation,
34452da9a59SGnoCiYeH     ) {
34552da9a59SGnoCiYeH         let mut fbcon_data = self.fbcon_data();
34652da9a59SGnoCiYeH 
34752da9a59SGnoCiYeH         let c = vc_data.screen_buf[vc_data.pos];
34852da9a59SGnoCiYeH 
34952da9a59SGnoCiYeH         if vc_data.cursor_type.contains(VcCursor::CUR_SW) {
35052da9a59SGnoCiYeH             // 取消硬光标Timer,但是现在没有硬光标,先写在这
35152da9a59SGnoCiYeH         } else {
35252da9a59SGnoCiYeH             // 添加硬光标Timer
35352da9a59SGnoCiYeH         }
35452da9a59SGnoCiYeH 
35552da9a59SGnoCiYeH         fbcon_data.cursor_flash = op != CursorOperation::Erase;
35652da9a59SGnoCiYeH 
35752da9a59SGnoCiYeH         drop(fbcon_data);
35852da9a59SGnoCiYeH 
35952da9a59SGnoCiYeH         self.cursor(
36052da9a59SGnoCiYeH             vc_data,
36152da9a59SGnoCiYeH             op,
36252da9a59SGnoCiYeH             self.get_color(vc_data, c, true),
36352da9a59SGnoCiYeH             self.get_color(vc_data, c, false),
36452da9a59SGnoCiYeH         );
36552da9a59SGnoCiYeH     }
36652da9a59SGnoCiYeH 
36752da9a59SGnoCiYeH     fn con_set_palette(
36852da9a59SGnoCiYeH         &self,
36952da9a59SGnoCiYeH         vc_data: &VirtualConsoleData,
37052da9a59SGnoCiYeH         color_table: &[u8],
37152da9a59SGnoCiYeH     ) -> Result<(), SystemError> {
37252da9a59SGnoCiYeH         let fb_info = self.fb();
37352da9a59SGnoCiYeH         let depth = fb_info.color_depth();
37452da9a59SGnoCiYeH         let mut palette = Vec::new();
37552da9a59SGnoCiYeH         palette.resize(16, Color::default());
37652da9a59SGnoCiYeH         if depth > 3 {
37752da9a59SGnoCiYeH             let vc_palette = &vc_data.palette;
37852da9a59SGnoCiYeH             for i in 0..16 {
37952da9a59SGnoCiYeH                 let idx = color_table[i];
38052da9a59SGnoCiYeH                 let col = palette.get_mut(idx as usize).unwrap();
38152da9a59SGnoCiYeH                 col.red = (vc_palette[i].red << 8) | vc_palette[i].red;
38252da9a59SGnoCiYeH                 col.green = (vc_palette[i].green << 8) | vc_palette[i].green;
38352da9a59SGnoCiYeH                 col.blue = (vc_palette[i].blue << 8) | vc_palette[i].blue;
38452da9a59SGnoCiYeH             }
38552da9a59SGnoCiYeH         } else {
38652da9a59SGnoCiYeH             todo!()
38752da9a59SGnoCiYeH         }
38852da9a59SGnoCiYeH 
38952da9a59SGnoCiYeH         self.fb().set_color_map(palette)?;
39052da9a59SGnoCiYeH 
39152da9a59SGnoCiYeH         Ok(())
39252da9a59SGnoCiYeH     }
39352da9a59SGnoCiYeH 
39452bcb59eSGnoCiYeH     #[inline(never)]
39552da9a59SGnoCiYeH     fn con_scroll(
39652da9a59SGnoCiYeH         &self,
39752da9a59SGnoCiYeH         vc_data: &mut VirtualConsoleData,
39852da9a59SGnoCiYeH         top: usize,
39952da9a59SGnoCiYeH         bottom: usize,
40052da9a59SGnoCiYeH         dir: crate::driver::tty::virtual_terminal::virtual_console::ScrollDir,
40152da9a59SGnoCiYeH         mut count: usize,
40252da9a59SGnoCiYeH     ) -> bool {
40352da9a59SGnoCiYeH         self.con_cursor(vc_data, CursorOperation::Erase);
40452da9a59SGnoCiYeH 
40552da9a59SGnoCiYeH         let fbcon_data = self.fbcon_data();
40652da9a59SGnoCiYeH         let scroll_mode = fbcon_data.display.scroll_mode;
40752da9a59SGnoCiYeH 
40852da9a59SGnoCiYeH         drop(fbcon_data);
40952da9a59SGnoCiYeH 
41052da9a59SGnoCiYeH         match dir {
41152da9a59SGnoCiYeH             ScrollDir::Up => {
41252da9a59SGnoCiYeH                 if count > vc_data.rows {
41352da9a59SGnoCiYeH                     count = vc_data.rows;
41452da9a59SGnoCiYeH                 }
41552da9a59SGnoCiYeH 
41652da9a59SGnoCiYeH                 match scroll_mode {
41752da9a59SGnoCiYeH                     ScrollMode::Move => {
41852da9a59SGnoCiYeH                         let start = top * vc_data.cols;
41952da9a59SGnoCiYeH                         let end = bottom * vc_data.cols;
42052da9a59SGnoCiYeH                         vc_data.screen_buf[start..end].rotate_left(count * vc_data.cols);
42152da9a59SGnoCiYeH 
42252da9a59SGnoCiYeH                         let _ = self.bmove(
42352da9a59SGnoCiYeH                             vc_data,
42452da9a59SGnoCiYeH                             top as i32,
42552da9a59SGnoCiYeH                             0,
42652da9a59SGnoCiYeH                             top as i32 - count as i32,
42752da9a59SGnoCiYeH                             0,
42852da9a59SGnoCiYeH                             (bottom - top) as u32,
42952da9a59SGnoCiYeH                             vc_data.cols as u32,
43052da9a59SGnoCiYeH                         );
43152da9a59SGnoCiYeH 
43252da9a59SGnoCiYeH                         let _ = self.con_clear(vc_data, bottom - count, 0, count, vc_data.cols);
43352da9a59SGnoCiYeH 
43452da9a59SGnoCiYeH                         let offset = vc_data.cols * (bottom - count);
43552da9a59SGnoCiYeH                         for i in
43652da9a59SGnoCiYeH                             vc_data.screen_buf[offset..(offset + (vc_data.cols * count))].iter_mut()
43752da9a59SGnoCiYeH                         {
43852da9a59SGnoCiYeH                             *i = vc_data.erase_char;
43952da9a59SGnoCiYeH                         }
44052da9a59SGnoCiYeH 
44152da9a59SGnoCiYeH                         return true;
44252da9a59SGnoCiYeH                     }
44352da9a59SGnoCiYeH                     ScrollMode::PanMove => todo!(),
44452da9a59SGnoCiYeH                     ScrollMode::WrapMove => todo!(),
44552da9a59SGnoCiYeH                     ScrollMode::Redraw => {
44652da9a59SGnoCiYeH                         let start = top * vc_data.cols;
44752da9a59SGnoCiYeH                         let end = bottom * vc_data.cols;
44852da9a59SGnoCiYeH                         vc_data.screen_buf[start..end].rotate_left(count * vc_data.cols);
44952da9a59SGnoCiYeH 
45052da9a59SGnoCiYeH                         let data = &vc_data.screen_buf[start..(bottom - count) * vc_data.cols];
45152da9a59SGnoCiYeH 
45252da9a59SGnoCiYeH                         for line in top..(bottom - count) {
45352da9a59SGnoCiYeH                             let mut start = line * vc_data.cols;
45452da9a59SGnoCiYeH                             let end = start + vc_data.cols;
45552da9a59SGnoCiYeH                             let mut offset = start;
45652da9a59SGnoCiYeH                             let mut attr = 1;
45752da9a59SGnoCiYeH                             let mut x = 0;
45852da9a59SGnoCiYeH                             while offset < end {
45952da9a59SGnoCiYeH                                 let c = data[offset];
46052da9a59SGnoCiYeH 
46152da9a59SGnoCiYeH                                 if attr != c & 0xff00 {
46252da9a59SGnoCiYeH                                     // 属性变化,输出完上一个的并且更新属性
46352da9a59SGnoCiYeH                                     attr = c & 0xff00;
46452da9a59SGnoCiYeH 
46552da9a59SGnoCiYeH                                     let count = offset - start;
46652da9a59SGnoCiYeH                                     let _ = self.con_putcs(
46752da9a59SGnoCiYeH                                         vc_data,
46852da9a59SGnoCiYeH                                         &data[start..offset],
46952da9a59SGnoCiYeH                                         count,
47052da9a59SGnoCiYeH                                         line as u32,
47152da9a59SGnoCiYeH                                         x,
47252da9a59SGnoCiYeH                                     );
47352da9a59SGnoCiYeH                                     start = offset;
47452da9a59SGnoCiYeH                                     x += count as u32;
47552da9a59SGnoCiYeH                                 }
47652da9a59SGnoCiYeH 
47752da9a59SGnoCiYeH                                 offset += 1;
47852da9a59SGnoCiYeH                             }
47952da9a59SGnoCiYeH                             let _ = self.con_putcs(
48052da9a59SGnoCiYeH                                 vc_data,
48152da9a59SGnoCiYeH                                 &data[start..offset],
48252da9a59SGnoCiYeH                                 offset - start,
48352da9a59SGnoCiYeH                                 line as u32,
48452da9a59SGnoCiYeH                                 x,
48552da9a59SGnoCiYeH                             );
48652da9a59SGnoCiYeH                         }
48752da9a59SGnoCiYeH 
48852da9a59SGnoCiYeH                         let _ = self.con_clear(vc_data, bottom - count, 0, count, vc_data.cols);
48952da9a59SGnoCiYeH 
49052da9a59SGnoCiYeH                         let offset = vc_data.cols * (bottom - count);
49152da9a59SGnoCiYeH                         for i in
49252da9a59SGnoCiYeH                             vc_data.screen_buf[offset..(offset + (vc_data.cols * count))].iter_mut()
49352da9a59SGnoCiYeH                         {
49452da9a59SGnoCiYeH                             *i = vc_data.erase_char;
49552da9a59SGnoCiYeH                         }
49652da9a59SGnoCiYeH 
49752da9a59SGnoCiYeH                         return true;
49852da9a59SGnoCiYeH                     }
49952da9a59SGnoCiYeH                     ScrollMode::PanRedraw => todo!(),
50052da9a59SGnoCiYeH                 }
50152da9a59SGnoCiYeH             }
50252da9a59SGnoCiYeH             ScrollDir::Down => {
50352da9a59SGnoCiYeH                 if count > vc_data.rows {
50452da9a59SGnoCiYeH                     count = vc_data.rows;
50552da9a59SGnoCiYeH                 }
50652da9a59SGnoCiYeH 
50752da9a59SGnoCiYeH                 match scroll_mode {
50852bcb59eSGnoCiYeH                     ScrollMode::Move => {
50952bcb59eSGnoCiYeH                         let start = top * vc_data.cols;
51052bcb59eSGnoCiYeH                         let end = bottom * vc_data.cols;
51152bcb59eSGnoCiYeH                         vc_data.screen_buf[start..end].rotate_right(count * vc_data.cols);
51252bcb59eSGnoCiYeH 
51352bcb59eSGnoCiYeH                         let _ = self.bmove(
51452bcb59eSGnoCiYeH                             vc_data,
51552bcb59eSGnoCiYeH                             top as i32,
51652bcb59eSGnoCiYeH                             0,
51752bcb59eSGnoCiYeH                             top as i32 + count as i32,
51852bcb59eSGnoCiYeH                             0,
51952bcb59eSGnoCiYeH                             (bottom - top - count) as u32,
52052bcb59eSGnoCiYeH                             vc_data.cols as u32,
52152bcb59eSGnoCiYeH                         );
52252bcb59eSGnoCiYeH 
52352bcb59eSGnoCiYeH                         let _ = self.con_clear(vc_data, top, 0, count, vc_data.cols);
52452bcb59eSGnoCiYeH 
52552bcb59eSGnoCiYeH                         let offset = vc_data.cols * count;
52652bcb59eSGnoCiYeH                         for i in vc_data.screen_buf[start..(start + offset)].iter_mut() {
52752bcb59eSGnoCiYeH                             *i = vc_data.erase_char;
52852bcb59eSGnoCiYeH                         }
52952bcb59eSGnoCiYeH 
53052bcb59eSGnoCiYeH                         return true;
53152bcb59eSGnoCiYeH                     }
53252da9a59SGnoCiYeH                     ScrollMode::PanMove => todo!(),
53352da9a59SGnoCiYeH                     ScrollMode::WrapMove => todo!(),
53452da9a59SGnoCiYeH                     ScrollMode::Redraw => {
53552da9a59SGnoCiYeH                         // self.scroll_redraw(
53652da9a59SGnoCiYeH                         //     vc_data,
53752da9a59SGnoCiYeH                         //     bottom - 1,
53852da9a59SGnoCiYeH                         //     bottom - top - count,
53952da9a59SGnoCiYeH                         //     count * vc_data.cols,
54052da9a59SGnoCiYeH                         //     false,
54152da9a59SGnoCiYeH                         // );
54252da9a59SGnoCiYeH 
54352da9a59SGnoCiYeH                         let _ = self.con_clear(vc_data, top, 0, count, vc_data.cols);
54452da9a59SGnoCiYeH 
54552da9a59SGnoCiYeH                         let offset = vc_data.cols * top;
54652da9a59SGnoCiYeH                         for i in
54752da9a59SGnoCiYeH                             vc_data.screen_buf[offset..(offset + (vc_data.cols * count))].iter_mut()
54852da9a59SGnoCiYeH                         {
54952da9a59SGnoCiYeH                             *i = vc_data.erase_char;
55052da9a59SGnoCiYeH                         }
55152da9a59SGnoCiYeH 
55252da9a59SGnoCiYeH                         return true;
55352da9a59SGnoCiYeH                     }
55452da9a59SGnoCiYeH                     ScrollMode::PanRedraw => todo!(),
55552da9a59SGnoCiYeH                 }
55652da9a59SGnoCiYeH             }
55752da9a59SGnoCiYeH         }
55852da9a59SGnoCiYeH     }
55952da9a59SGnoCiYeH }
56052da9a59SGnoCiYeH 
56152da9a59SGnoCiYeH impl FrameBufferConsole for BlittingFbConsole {
56252da9a59SGnoCiYeH     fn bmove(
56352da9a59SGnoCiYeH         &self,
56452da9a59SGnoCiYeH         vc_data: &VirtualConsoleData,
56552da9a59SGnoCiYeH         sy: i32,
56652da9a59SGnoCiYeH         sx: i32,
56752da9a59SGnoCiYeH         dy: i32,
56852da9a59SGnoCiYeH         dx: i32,
56952da9a59SGnoCiYeH         height: u32,
57052da9a59SGnoCiYeH         width: u32,
57152da9a59SGnoCiYeH     ) -> Result<(), SystemError> {
57252da9a59SGnoCiYeH         let area = CopyAreaData::new(
57352da9a59SGnoCiYeH             dx * vc_data.font.width as i32,
57452da9a59SGnoCiYeH             dy * vc_data.font.height as i32,
57552da9a59SGnoCiYeH             width * vc_data.font.width,
57652da9a59SGnoCiYeH             height * vc_data.font.height,
57752da9a59SGnoCiYeH             sx * vc_data.font.width as i32,
57852da9a59SGnoCiYeH             sy * vc_data.font.height as i32,
57952da9a59SGnoCiYeH         );
58052da9a59SGnoCiYeH 
58152bcb59eSGnoCiYeH         self.fb().fb_copyarea(area);
58252bcb59eSGnoCiYeH         Ok(())
58352da9a59SGnoCiYeH     }
58452da9a59SGnoCiYeH 
58552da9a59SGnoCiYeH     fn clear(
58652da9a59SGnoCiYeH         &self,
58752da9a59SGnoCiYeH         vc_data: &VirtualConsoleData,
58852da9a59SGnoCiYeH         sy: u32,
58952da9a59SGnoCiYeH         sx: u32,
59052da9a59SGnoCiYeH         height: u32,
59152da9a59SGnoCiYeH         width: u32,
59252da9a59SGnoCiYeH     ) -> Result<(), SystemError> {
59352da9a59SGnoCiYeH         let region = FillRectData::new(
59452da9a59SGnoCiYeH             sx * vc_data.font.width,
59552da9a59SGnoCiYeH             sy * vc_data.font.height,
59652da9a59SGnoCiYeH             width * vc_data.font.width,
59752da9a59SGnoCiYeH             height * vc_data.font.height,
59852da9a59SGnoCiYeH             self.get_color(vc_data, vc_data.erase_char, false),
59952da9a59SGnoCiYeH             FillRectROP::Copy,
60052da9a59SGnoCiYeH         );
60152da9a59SGnoCiYeH 
60252da9a59SGnoCiYeH         self.fb().fb_fillrect(region)?;
60352da9a59SGnoCiYeH 
60452da9a59SGnoCiYeH         Ok(())
60552da9a59SGnoCiYeH     }
60652da9a59SGnoCiYeH 
60752da9a59SGnoCiYeH     fn put_string(
60852da9a59SGnoCiYeH         &self,
60952da9a59SGnoCiYeH         vc_data: &VirtualConsoleData,
61052da9a59SGnoCiYeH         data: &[u16],
61152da9a59SGnoCiYeH         mut count: u32,
61252da9a59SGnoCiYeH         y: u32,
61352da9a59SGnoCiYeH         x: u32,
61452da9a59SGnoCiYeH         fg: u32,
61552da9a59SGnoCiYeH         bg: u32,
61652da9a59SGnoCiYeH     ) -> Result<(), SystemError> {
61752da9a59SGnoCiYeH         // 向上取整
61852da9a59SGnoCiYeH         let width = (vc_data.font.width + 7) / 8;
61952da9a59SGnoCiYeH         let cellsize = width * vc_data.font.height;
62052da9a59SGnoCiYeH         let fb_info = self.fb();
62152da9a59SGnoCiYeH         // 一次能输出的最大字数,避免帧缓冲区溢出
62252da9a59SGnoCiYeH         let max_cnt = (fb_info.current_fb_var().xres * fb_info.current_fb_var().yres) / cellsize;
62352da9a59SGnoCiYeH         let attr = FbConAttr::get_attr(data[0], fb_info.color_depth());
62452da9a59SGnoCiYeH 
62552da9a59SGnoCiYeH         let mut image = FbImage {
62652da9a59SGnoCiYeH             x: x * vc_data.font.width,
62752da9a59SGnoCiYeH             y: y * vc_data.font.height,
62852da9a59SGnoCiYeH             width: 0,
62952da9a59SGnoCiYeH             height: vc_data.font.height,
63052da9a59SGnoCiYeH             fg,
63152da9a59SGnoCiYeH             bg,
63252da9a59SGnoCiYeH             depth: 1,
63352da9a59SGnoCiYeH             data: Default::default(),
63452da9a59SGnoCiYeH         };
63552da9a59SGnoCiYeH 
63652da9a59SGnoCiYeH         image.data.resize(cellsize as usize * count as usize, 0);
63752da9a59SGnoCiYeH 
63852da9a59SGnoCiYeH         while count > 0 {
63952da9a59SGnoCiYeH             let cnt = count.min(max_cnt);
64052da9a59SGnoCiYeH 
64152da9a59SGnoCiYeH             image.width = vc_data.font.width * cnt;
64252da9a59SGnoCiYeH 
64352da9a59SGnoCiYeH             self.bit_put_string(vc_data, data, attr, cnt, cellsize, &mut image);
64452da9a59SGnoCiYeH 
64552da9a59SGnoCiYeH             image.x += cnt * vc_data.font.width;
64652da9a59SGnoCiYeH             count -= cnt;
64752da9a59SGnoCiYeH         }
64852da9a59SGnoCiYeH 
64952da9a59SGnoCiYeH         Ok(())
65052da9a59SGnoCiYeH     }
65152da9a59SGnoCiYeH 
65252da9a59SGnoCiYeH     fn fbcon_data(&self) -> SpinLockGuard<super::FrameBufferConsoleData> {
65352da9a59SGnoCiYeH         self.fbcon_data.lock()
65452da9a59SGnoCiYeH     }
65552da9a59SGnoCiYeH 
65652da9a59SGnoCiYeH     fn cursor(&self, vc_data: &VirtualConsoleData, op: CursorOperation, fg: u32, bg: u32) {
65752da9a59SGnoCiYeH         let mut fbcon_data = self.fbcon_data();
65852da9a59SGnoCiYeH         let fb_info = self.fb();
65952da9a59SGnoCiYeH         let mut cursor = FbCursor::default();
66052da9a59SGnoCiYeH         let charmask = if vc_data.hi_font_mask != 0 {
66152da9a59SGnoCiYeH             0x1ff
66252da9a59SGnoCiYeH         } else {
66352da9a59SGnoCiYeH             0xff
66452da9a59SGnoCiYeH         };
66552da9a59SGnoCiYeH 
66652da9a59SGnoCiYeH         // 向上取整
66752da9a59SGnoCiYeH         let w = (vc_data.font.width + 7) / 8;
66852da9a59SGnoCiYeH         let y = fbcon_data.display.real_y(vc_data.state.y as u32);
66952da9a59SGnoCiYeH 
67052da9a59SGnoCiYeH         let c = vc_data.screen_buf[vc_data.pos];
67152da9a59SGnoCiYeH         let attr = FbConAttr::get_attr(c, fb_info.color_depth());
67252da9a59SGnoCiYeH         let char_offset = (c as usize & charmask) * ((w * vc_data.font.height) as usize);
67352da9a59SGnoCiYeH 
674b5b571e0SLoGin         if fbcon_data.cursor_state.image.data != vc_data.font.data[char_offset..]
67552da9a59SGnoCiYeH             || fbcon_data.cursor_reset
67652da9a59SGnoCiYeH         {
67752da9a59SGnoCiYeH             fbcon_data.cursor_state.image.data = vc_data.font.data[char_offset..].to_vec();
67852da9a59SGnoCiYeH             cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETIMAGE);
67952da9a59SGnoCiYeH         }
68052da9a59SGnoCiYeH 
68152da9a59SGnoCiYeH         if !attr.is_empty() {
68252da9a59SGnoCiYeH             fbcon_data
68352da9a59SGnoCiYeH                 .cursor_data
68452da9a59SGnoCiYeH                 .resize(w as usize * vc_data.font.height as usize, 0);
68552da9a59SGnoCiYeH 
68652da9a59SGnoCiYeH             attr.update_attr(
68752da9a59SGnoCiYeH                 &mut fbcon_data.cursor_data,
68852da9a59SGnoCiYeH                 &vc_data.font.data[char_offset..],
68952da9a59SGnoCiYeH                 vc_data,
69052da9a59SGnoCiYeH             );
69152da9a59SGnoCiYeH         }
69252da9a59SGnoCiYeH 
69352da9a59SGnoCiYeH         if fbcon_data.cursor_state.image.fg != fg
69452da9a59SGnoCiYeH             || fbcon_data.cursor_state.image.bg != bg
69552da9a59SGnoCiYeH             || fbcon_data.cursor_reset
69652da9a59SGnoCiYeH         {
69752da9a59SGnoCiYeH             fbcon_data.cursor_state.image.fg = fg;
69852da9a59SGnoCiYeH             fbcon_data.cursor_state.image.bg = bg;
69952da9a59SGnoCiYeH             cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETCMAP);
70052da9a59SGnoCiYeH         }
70152da9a59SGnoCiYeH 
70252da9a59SGnoCiYeH         if fbcon_data.cursor_state.image.x != (vc_data.font.width * vc_data.state.x as u32)
70352da9a59SGnoCiYeH             || fbcon_data.cursor_state.image.y != (vc_data.font.height * y)
70452da9a59SGnoCiYeH             || fbcon_data.cursor_reset
70552da9a59SGnoCiYeH         {
70652da9a59SGnoCiYeH             fbcon_data.cursor_state.image.x = vc_data.font.width * vc_data.state.x as u32;
70752da9a59SGnoCiYeH             fbcon_data.cursor_state.image.y = vc_data.font.height * y;
70852da9a59SGnoCiYeH             cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETPOS);
70952da9a59SGnoCiYeH         }
71052da9a59SGnoCiYeH 
71152da9a59SGnoCiYeH         if fbcon_data.cursor_state.image.height != vc_data.font.height
71252da9a59SGnoCiYeH             || fbcon_data.cursor_state.image.width != vc_data.font.width
71352da9a59SGnoCiYeH             || fbcon_data.cursor_reset
71452da9a59SGnoCiYeH         {
71552da9a59SGnoCiYeH             fbcon_data.cursor_state.image.height = vc_data.font.height;
71652da9a59SGnoCiYeH             fbcon_data.cursor_state.image.width = vc_data.font.width;
71752da9a59SGnoCiYeH             cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETSIZE);
71852da9a59SGnoCiYeH         }
71952da9a59SGnoCiYeH 
72052da9a59SGnoCiYeH         if fbcon_data.cursor_state.hot_x > 0
72152da9a59SGnoCiYeH             || fbcon_data.cursor_state.hot_y > 0
72252da9a59SGnoCiYeH             || fbcon_data.cursor_reset
72352da9a59SGnoCiYeH         {
72452da9a59SGnoCiYeH             fbcon_data.cursor_state.hot_x = 0;
72552da9a59SGnoCiYeH             cursor.hot_y = 0;
72652da9a59SGnoCiYeH             cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETHOT);
72752da9a59SGnoCiYeH         }
72852da9a59SGnoCiYeH 
72952da9a59SGnoCiYeH         if cursor.set_mode.contains(FbCursorSetMode::FB_CUR_SETSIZE)
73052da9a59SGnoCiYeH             || vc_data.cursor_type != fbcon_data.display.cursor_shape
73152da9a59SGnoCiYeH             || fbcon_data.cursor_state.mask.is_empty()
73252da9a59SGnoCiYeH             || fbcon_data.cursor_reset
73352da9a59SGnoCiYeH         {
73452da9a59SGnoCiYeH             fbcon_data.display.cursor_shape = vc_data.cursor_type;
73552da9a59SGnoCiYeH             cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETSHAPE);
73652da9a59SGnoCiYeH 
73752da9a59SGnoCiYeH             let cur_height;
73852da9a59SGnoCiYeH             match fbcon_data.display.cursor_shape.cursor_size() {
73952da9a59SGnoCiYeH                 VcCursor::CUR_NONE => {
74052da9a59SGnoCiYeH                     cur_height = 0;
74152da9a59SGnoCiYeH                 }
74252da9a59SGnoCiYeH                 VcCursor::CUR_UNDERLINE => {
74352da9a59SGnoCiYeH                     if vc_data.font.height < 10 {
74452da9a59SGnoCiYeH                         cur_height = 1;
74552da9a59SGnoCiYeH                     } else {
74652da9a59SGnoCiYeH                         cur_height = 2;
74752da9a59SGnoCiYeH                     }
74852da9a59SGnoCiYeH                 }
74952da9a59SGnoCiYeH                 VcCursor::CUR_LOWER_THIRD => {
75052da9a59SGnoCiYeH                     cur_height = vc_data.font.height / 3;
75152da9a59SGnoCiYeH                 }
75252da9a59SGnoCiYeH                 VcCursor::CUR_LOWER_HALF => {
75352da9a59SGnoCiYeH                     cur_height = vc_data.font.height >> 1;
75452da9a59SGnoCiYeH                 }
75552da9a59SGnoCiYeH                 VcCursor::CUR_TWO_THIRDS => {
75652da9a59SGnoCiYeH                     cur_height = (vc_data.font.height << 1) / 3;
75752da9a59SGnoCiYeH                 }
75852da9a59SGnoCiYeH                 _ => {
75952da9a59SGnoCiYeH                     cur_height = vc_data.font.height;
76052da9a59SGnoCiYeH                 }
76152da9a59SGnoCiYeH             }
76252da9a59SGnoCiYeH 
76352da9a59SGnoCiYeH             // 表示空白部分
76452da9a59SGnoCiYeH             let mut size = (vc_data.font.height - cur_height) * w;
76552da9a59SGnoCiYeH             while size > 0 {
76652da9a59SGnoCiYeH                 size -= 1;
76752da9a59SGnoCiYeH                 fbcon_data.cursor_state.mask.push(0x00);
76852da9a59SGnoCiYeH             }
76952da9a59SGnoCiYeH             size = cur_height * w;
77052da9a59SGnoCiYeH             // 表示光标显示部分
77152da9a59SGnoCiYeH             while size > 0 {
77252da9a59SGnoCiYeH                 size -= 1;
77352da9a59SGnoCiYeH                 fbcon_data.cursor_state.mask.push(0xff);
77452da9a59SGnoCiYeH             }
77552da9a59SGnoCiYeH         }
77652da9a59SGnoCiYeH 
77752da9a59SGnoCiYeH         match op {
77852da9a59SGnoCiYeH             CursorOperation::Erase => {
77952da9a59SGnoCiYeH                 fbcon_data.cursor_state.enable = false;
78052da9a59SGnoCiYeH             }
78152da9a59SGnoCiYeH             _ => {
78252da9a59SGnoCiYeH                 fbcon_data.cursor_state.enable = !vc_data.cursor_type.contains(VcCursor::CUR_SW);
78352da9a59SGnoCiYeH             }
78452da9a59SGnoCiYeH         }
78552da9a59SGnoCiYeH 
78652da9a59SGnoCiYeH         if !attr.is_empty() {
78752da9a59SGnoCiYeH             cursor.image.data = fbcon_data.cursor_data.clone();
78852da9a59SGnoCiYeH         } else {
78952da9a59SGnoCiYeH             cursor.image.data = vc_data.font.data
79052da9a59SGnoCiYeH                 [char_offset..char_offset + (w as usize * vc_data.font.height as usize)]
79152da9a59SGnoCiYeH                 .to_vec();
79252da9a59SGnoCiYeH         }
79352da9a59SGnoCiYeH         cursor.image.fg = fbcon_data.cursor_state.image.fg;
79452da9a59SGnoCiYeH         cursor.image.bg = fbcon_data.cursor_state.image.bg;
79552da9a59SGnoCiYeH         cursor.image.x = fbcon_data.cursor_state.image.x;
79652da9a59SGnoCiYeH         cursor.image.y = fbcon_data.cursor_state.image.y;
79752da9a59SGnoCiYeH         cursor.image.height = fbcon_data.cursor_state.image.height;
79852da9a59SGnoCiYeH         cursor.image.width = fbcon_data.cursor_state.image.width;
79952da9a59SGnoCiYeH         cursor.hot_x = fbcon_data.cursor_state.hot_x;
80052da9a59SGnoCiYeH         cursor.hot_y = fbcon_data.cursor_state.hot_y;
80152da9a59SGnoCiYeH         cursor.mask = fbcon_data.cursor_state.mask.clone();
80252da9a59SGnoCiYeH         cursor.enable = fbcon_data.cursor_state.enable;
80352da9a59SGnoCiYeH         cursor.image.depth = 1;
80452da9a59SGnoCiYeH         cursor.rop = true;
80552da9a59SGnoCiYeH 
80652da9a59SGnoCiYeH         if fb_info.fb_cursor(&cursor).is_err() {
80752da9a59SGnoCiYeH             let _ = fb_info.soft_cursor(cursor);
80852da9a59SGnoCiYeH         }
80952da9a59SGnoCiYeH 
81052da9a59SGnoCiYeH         fbcon_data.cursor_reset = false;
81152da9a59SGnoCiYeH     }
81252da9a59SGnoCiYeH }
813