xref: /DragonOS/kernel/src/driver/video/fbdev/base/fbcon/framebuffer_console.rs (revision 52dc4c3ee87b31fee4f567f776fd8ad58fbfd9a5)
1 use alloc::{sync::Arc, vec::Vec};
2 use log::warn;
3 use system_error::SystemError;
4 
5 use crate::{
6     driver::{
7         tty::{
8             console::ConsoleSwitch,
9             virtual_terminal::{
10                 virtual_console::{CursorOperation, ScrollDir, VcCursor, VirtualConsoleData},
11                 Color, VirtConsole,
12             },
13         },
14         video::fbdev::base::{
15             CopyAreaData, FbCursor, FbCursorSetMode, FbImage, FbVisual, FillRectData, FillRectROP,
16             FrameBuffer, ScrollMode, FRAME_BUFFER_SET,
17         },
18     },
19     libs::{
20         font::FontDesc,
21         spinlock::{SpinLock, SpinLockGuard},
22     },
23 };
24 
25 use super::{FbConAttr, FrameBufferConsole, FrameBufferConsoleData};
26 
27 #[derive(Debug)]
28 pub struct BlittingFbConsole {
29     fb: SpinLock<Option<Arc<dyn FrameBuffer>>>,
30     fbcon_data: SpinLock<FrameBufferConsoleData>,
31 }
32 
33 unsafe impl Send for BlittingFbConsole {}
34 unsafe impl Sync for BlittingFbConsole {}
35 
36 impl BlittingFbConsole {
37     pub fn new() -> Result<Self, SystemError> {
38         Ok(Self {
39             fb: SpinLock::new(None),
40             fbcon_data: SpinLock::new(FrameBufferConsoleData::default()),
41         })
42     }
43 
44     fn fb(&self) -> Arc<dyn FrameBuffer> {
45         self.fb.lock().clone().unwrap()
46     }
47 
48     fn get_color(&self, vc_data: &VirtualConsoleData, c: u16, is_fg: bool) -> u32 {
49         let fb_info = self.fb();
50         let mut color = 0;
51 
52         let depth = fb_info.color_depth();
53 
54         if depth != 1 {
55             if is_fg {
56                 let fg_shift = if vc_data.hi_font_mask != 0 { 9 } else { 8 };
57                 color = (c as u32 >> fg_shift) & 0x0f
58             } else {
59                 let bg_shift = if vc_data.hi_font_mask != 0 { 13 } else { 12 };
60                 color = (c as u32 >> bg_shift) & 0x0f
61             }
62         }
63 
64         match depth {
65             1 => {
66                 let col = self.mono_color();
67                 let fg;
68                 let bg;
69                 if fb_info.current_fb_fix().visual != FbVisual::Mono01 {
70                     fg = col;
71                     bg = 0;
72                 } else {
73                     fg = 0;
74                     bg = col;
75                 }
76                 color = if is_fg { fg } else { bg };
77             }
78             2 => {
79                 /*
80                     颜色深度为2,即16色,
81                    将16色的颜色值映射到4色的灰度,
82                    其中颜色0映射为黑色,颜色1到6映射为白色,
83                    颜色7到8映射为灰色,其他颜色映射为强烈的白色。
84                 */
85                 if (1..=6).contains(&color) {
86                     // 白色
87                     color = 2;
88                 } else if (7..=8).contains(&color) {
89                     // 灰色
90                     color = 1;
91                 } else {
92                     // 强白
93                     color = 3;
94                 }
95             }
96             3 => {
97                 /*
98                    颜色深度为3,即256色,仅保留颜色的低3位,即颜色 0 到 7
99                 */
100                 color &= 7;
101             }
102             _ => {}
103         }
104         color
105     }
106 
107     /// ## 计算单色调的函数
108     fn mono_color(&self) -> u32 {
109         let fb_info = self.fb();
110         let mut max_len = fb_info
111             .current_fb_var()
112             .green
113             .length
114             .max(fb_info.current_fb_var().red.length);
115 
116         max_len = max_len.max(fb_info.current_fb_var().blue.length);
117 
118         return (!(0xfff << max_len)) & 0xff;
119     }
120 
121     fn bit_put_string(
122         &self,
123         vc_data: &VirtualConsoleData,
124         buf: &[u16],
125         attr: FbConAttr,
126         cnt: u32,
127         cellsize: u32,
128         image: &mut FbImage,
129     ) {
130         let charmask = if vc_data.hi_font_mask != 0 {
131             0x1ff
132         } else {
133             0xff
134         };
135 
136         let mut offset;
137         let image_line_byte = image.width as usize / 8;
138 
139         let byte_width = vc_data.font.width as usize / 8;
140         let font_height = vc_data.font.height as usize;
141         // let mut char_offset = 0;
142         for (char_offset, char_item) in buf.iter().enumerate().take(cnt as usize) {
143             // 在字符表中的index
144             let ch = char_item & charmask;
145             // 计算出在font表中的偏移量
146             let font_offset = ch as usize * cellsize as usize;
147             let font_offset_end = font_offset + cellsize as usize;
148             // 设置image的data
149 
150             let src = &vc_data.font.data[font_offset..font_offset_end];
151             let mut dst = vec![0; src.len()];
152             dst.copy_from_slice(src);
153 
154             if !attr.is_empty() {
155                 attr.update_attr(&mut dst, src, vc_data)
156             }
157 
158             offset = char_offset * byte_width;
159             let mut dst_offset = 0;
160             for _ in 0..font_height {
161                 let dst_offset_next = dst_offset + byte_width;
162                 image.data[offset..offset + byte_width]
163                     .copy_from_slice(&dst[dst_offset..dst_offset_next]);
164 
165                 offset += image_line_byte;
166                 dst_offset = dst_offset_next;
167             }
168         }
169 
170         self.fb().fb_image_blit(image);
171     }
172 }
173 
174 impl ConsoleSwitch for BlittingFbConsole {
175     fn con_init(
176         &self,
177         _vc: &Arc<VirtConsole>,
178         vc_data: &mut VirtualConsoleData,
179         init: bool,
180     ) -> Result<(), system_error::SystemError> {
181         let fb_set_guard = FRAME_BUFFER_SET.read();
182         let fb = fb_set_guard.get(vc_data.index);
183         if fb.is_none() {
184             return Err(SystemError::EINVAL);
185         }
186         let fb = fb.unwrap();
187         if fb.is_none() {
188             panic!(
189                 "The Framebuffer with FbID {} has not been initialized yet.",
190                 vc_data.index
191             )
192         }
193 
194         let fb = fb.as_ref().unwrap().clone();
195 
196         if init {
197             // 初始化字体
198             let var = fb.current_fb_var();
199             let font = FontDesc::get_default_font(var.xres, var.yres, 0, 0);
200             vc_data.font.data = font.data.to_vec();
201             vc_data.font.width = font.width;
202             vc_data.font.height = font.height;
203             vc_data.font.count = font.char_count;
204         } else {
205             warn!("The frontend Framebuffer is not implemented");
206         }
207 
208         vc_data.color_mode = fb.color_depth() != 1;
209         vc_data.complement_mask = if vc_data.color_mode { 0x7700 } else { 0x0800 };
210 
211         if vc_data.font.count == 256 {
212             // ascii
213             vc_data.hi_font_mask = 0;
214         } else {
215             vc_data.hi_font_mask = 0x100;
216             if vc_data.color_mode {
217                 vc_data.complement_mask <<= 1;
218             }
219         }
220 
221         // TODO: 考虑rotate
222         if init {
223             vc_data.cols = (fb.current_fb_var().xres / vc_data.font.width) as usize;
224             vc_data.rows = (fb.current_fb_var().yres / vc_data.font.height) as usize;
225 
226             vc_data.pos = vc_data.state.x + vc_data.state.y * vc_data.cols;
227 
228             let new_size = vc_data.cols * vc_data.rows;
229             vc_data.screen_buf.resize(new_size, 0);
230         } else {
231             unimplemented!("Resize is not supported at the moment!");
232         }
233 
234         // 初始化fb
235         *self.fb.lock() = Some(fb);
236 
237         Ok(())
238     }
239 
240     fn con_deinit(&self) -> Result<(), system_error::SystemError> {
241         todo!()
242     }
243 
244     fn con_clear(
245         &self,
246         vc_data: &mut VirtualConsoleData,
247         sy: usize,
248         sx: usize,
249         height: usize,
250         width: usize,
251     ) -> Result<(), system_error::SystemError> {
252         let fb_data = self.fbcon_data();
253 
254         if height == 0 || width == 0 {
255             return Ok(());
256         }
257 
258         let y_break = (fb_data.display.virt_rows - fb_data.display.yscroll) as usize;
259         if sy < y_break && sy + height > y_break {
260             // 分两次clear
261             let b = y_break - sy;
262             let _ = self.clear(
263                 vc_data,
264                 fb_data.display.real_y(sy as u32),
265                 sx as u32,
266                 b as u32,
267                 width as u32,
268             );
269             let _ = self.clear(
270                 vc_data,
271                 fb_data.display.real_y((sy + b) as u32),
272                 sx as u32,
273                 (height - b) as u32,
274                 width as u32,
275             );
276         } else {
277             let _ = self.clear(
278                 vc_data,
279                 fb_data.display.real_y(sy as u32),
280                 sx as u32,
281                 height as u32,
282                 width as u32,
283             );
284         }
285 
286         Ok(())
287     }
288 
289     fn con_putc(
290         &self,
291         vc_data: &VirtualConsoleData,
292         ch: u16,
293         xpos: u32,
294         ypos: u32,
295     ) -> Result<(), system_error::SystemError> {
296         self.con_putcs(vc_data, &[ch], 1, ypos, xpos)
297     }
298 
299     fn con_putcs(
300         &self,
301         vc_data: &VirtualConsoleData,
302         buf: &[u16],
303         count: usize,
304         ypos: u32,
305         xpos: u32,
306     ) -> Result<(), SystemError> {
307         if count == 0 {
308             return Ok(());
309         }
310         let fbcon_data = self.fbcon_data();
311         let c = buf[0];
312         self.put_string(
313             vc_data,
314             buf,
315             count as u32,
316             fbcon_data.display.real_y(ypos),
317             xpos,
318             self.get_color(vc_data, c, true),
319             self.get_color(vc_data, c, false),
320         )
321     }
322 
323     fn con_getxy(
324         &self,
325         vc_data: &VirtualConsoleData,
326         pos: usize,
327     ) -> Result<(usize, usize, usize), SystemError> {
328         if pos < vc_data.screen_buf.len() {
329             let x = pos % vc_data.cols;
330             let y = pos / vc_data.cols;
331             let mut next_line_start = pos + (vc_data.cols - x);
332             if next_line_start >= vc_data.screen_buf.len() {
333                 next_line_start = 0
334             }
335             return Ok((next_line_start, x, y));
336         } else {
337             return Ok((0, 0, 0));
338         }
339     }
340 
341     #[allow(clippy::if_same_then_else)]
342     fn con_cursor(
343         &self,
344         vc_data: &VirtualConsoleData,
345         op: crate::driver::tty::virtual_terminal::virtual_console::CursorOperation,
346     ) {
347         let mut fbcon_data = self.fbcon_data();
348 
349         let c = vc_data.screen_buf[vc_data.pos];
350 
351         if vc_data.cursor_type.contains(VcCursor::CUR_SW) {
352             // 取消硬光标Timer,但是现在没有硬光标,先写在这
353         } else {
354             // 添加硬光标Timer
355         }
356 
357         fbcon_data.cursor_flash = op != CursorOperation::Erase;
358 
359         drop(fbcon_data);
360 
361         self.cursor(
362             vc_data,
363             op,
364             self.get_color(vc_data, c, true),
365             self.get_color(vc_data, c, false),
366         );
367     }
368 
369     fn con_set_palette(
370         &self,
371         vc_data: &VirtualConsoleData,
372         color_table: &[u8],
373     ) -> Result<(), SystemError> {
374         let fb_info = self.fb();
375         let depth = fb_info.color_depth();
376         let mut palette = Vec::new();
377         palette.resize(16, Color::default());
378         if depth > 3 {
379             let vc_palette = &vc_data.palette;
380             for i in 0..16 {
381                 let idx = color_table[i];
382                 let col = palette.get_mut(idx as usize).unwrap();
383                 col.red = (vc_palette[i].red << 8) | vc_palette[i].red;
384                 col.green = (vc_palette[i].green << 8) | vc_palette[i].green;
385                 col.blue = (vc_palette[i].blue << 8) | vc_palette[i].blue;
386             }
387         } else {
388             todo!()
389         }
390 
391         self.fb().set_color_map(palette)?;
392 
393         Ok(())
394     }
395 
396     #[inline(never)]
397     fn con_scroll(
398         &self,
399         vc_data: &mut VirtualConsoleData,
400         top: usize,
401         bottom: usize,
402         dir: crate::driver::tty::virtual_terminal::virtual_console::ScrollDir,
403         mut count: usize,
404     ) -> bool {
405         self.con_cursor(vc_data, CursorOperation::Erase);
406 
407         let fbcon_data = self.fbcon_data();
408         let scroll_mode = fbcon_data.display.scroll_mode;
409 
410         drop(fbcon_data);
411 
412         match dir {
413             ScrollDir::Up => {
414                 if count > vc_data.rows {
415                     count = vc_data.rows;
416                 }
417 
418                 match scroll_mode {
419                     ScrollMode::Move => {
420                         let start = top * vc_data.cols;
421                         let end = bottom * vc_data.cols;
422                         vc_data.screen_buf[start..end].rotate_left(count * vc_data.cols);
423 
424                         let _ = self.bmove(
425                             vc_data,
426                             top as i32,
427                             0,
428                             top as i32 - count as i32,
429                             0,
430                             (bottom - top) as u32,
431                             vc_data.cols as u32,
432                         );
433 
434                         let _ = self.con_clear(vc_data, bottom - count, 0, count, vc_data.cols);
435 
436                         let offset = vc_data.cols * (bottom - count);
437                         for i in
438                             vc_data.screen_buf[offset..(offset + (vc_data.cols * count))].iter_mut()
439                         {
440                             *i = vc_data.erase_char;
441                         }
442 
443                         return true;
444                     }
445                     ScrollMode::PanMove => todo!(),
446                     ScrollMode::WrapMove => todo!(),
447                     ScrollMode::Redraw => {
448                         let start = top * vc_data.cols;
449                         let end = bottom * vc_data.cols;
450                         vc_data.screen_buf[start..end].rotate_left(count * vc_data.cols);
451 
452                         let data = &vc_data.screen_buf[start..(bottom - count) * vc_data.cols];
453 
454                         for line in top..(bottom - count) {
455                             let mut start = line * vc_data.cols;
456                             let end = start + vc_data.cols;
457                             let mut offset = start;
458                             let mut attr = 1;
459                             let mut x = 0;
460                             while offset < end {
461                                 let c = data[offset];
462 
463                                 if attr != c & 0xff00 {
464                                     // 属性变化,输出完上一个的并且更新属性
465                                     attr = c & 0xff00;
466 
467                                     let count = offset - start;
468                                     let _ = self.con_putcs(
469                                         vc_data,
470                                         &data[start..offset],
471                                         count,
472                                         line as u32,
473                                         x,
474                                     );
475                                     start = offset;
476                                     x += count as u32;
477                                 }
478 
479                                 offset += 1;
480                             }
481                             let _ = self.con_putcs(
482                                 vc_data,
483                                 &data[start..offset],
484                                 offset - start,
485                                 line as u32,
486                                 x,
487                             );
488                         }
489 
490                         let _ = self.con_clear(vc_data, bottom - count, 0, count, vc_data.cols);
491 
492                         let offset = vc_data.cols * (bottom - count);
493                         for i in
494                             vc_data.screen_buf[offset..(offset + (vc_data.cols * count))].iter_mut()
495                         {
496                             *i = vc_data.erase_char;
497                         }
498 
499                         return true;
500                     }
501                     ScrollMode::PanRedraw => todo!(),
502                 }
503             }
504             ScrollDir::Down => {
505                 if count > vc_data.rows {
506                     count = vc_data.rows;
507                 }
508 
509                 match scroll_mode {
510                     ScrollMode::Move => {
511                         let start = top * vc_data.cols;
512                         let end = bottom * vc_data.cols;
513                         vc_data.screen_buf[start..end].rotate_right(count * vc_data.cols);
514 
515                         let _ = self.bmove(
516                             vc_data,
517                             top as i32,
518                             0,
519                             top as i32 + count as i32,
520                             0,
521                             (bottom - top - count) as u32,
522                             vc_data.cols as u32,
523                         );
524 
525                         let _ = self.con_clear(vc_data, top, 0, count, vc_data.cols);
526 
527                         let offset = vc_data.cols * count;
528                         for i in vc_data.screen_buf[start..(start + offset)].iter_mut() {
529                             *i = vc_data.erase_char;
530                         }
531 
532                         return true;
533                     }
534                     ScrollMode::PanMove => todo!(),
535                     ScrollMode::WrapMove => todo!(),
536                     ScrollMode::Redraw => {
537                         // self.scroll_redraw(
538                         //     vc_data,
539                         //     bottom - 1,
540                         //     bottom - top - count,
541                         //     count * vc_data.cols,
542                         //     false,
543                         // );
544 
545                         let _ = self.con_clear(vc_data, top, 0, count, vc_data.cols);
546 
547                         let offset = vc_data.cols * top;
548                         for i in
549                             vc_data.screen_buf[offset..(offset + (vc_data.cols * count))].iter_mut()
550                         {
551                             *i = vc_data.erase_char;
552                         }
553 
554                         return true;
555                     }
556                     ScrollMode::PanRedraw => todo!(),
557                 }
558             }
559         }
560     }
561 }
562 
563 impl FrameBufferConsole for BlittingFbConsole {
564     fn bmove(
565         &self,
566         vc_data: &VirtualConsoleData,
567         sy: i32,
568         sx: i32,
569         dy: i32,
570         dx: i32,
571         height: u32,
572         width: u32,
573     ) -> Result<(), SystemError> {
574         let area = CopyAreaData::new(
575             dx * vc_data.font.width as i32,
576             dy * vc_data.font.height as i32,
577             width * vc_data.font.width,
578             height * vc_data.font.height,
579             sx * vc_data.font.width as i32,
580             sy * vc_data.font.height as i32,
581         );
582 
583         self.fb().fb_copyarea(area);
584         Ok(())
585     }
586 
587     fn clear(
588         &self,
589         vc_data: &VirtualConsoleData,
590         sy: u32,
591         sx: u32,
592         height: u32,
593         width: u32,
594     ) -> Result<(), SystemError> {
595         let region = FillRectData::new(
596             sx * vc_data.font.width,
597             sy * vc_data.font.height,
598             width * vc_data.font.width,
599             height * vc_data.font.height,
600             self.get_color(vc_data, vc_data.erase_char, false),
601             FillRectROP::Copy,
602         );
603 
604         self.fb().fb_fillrect(region)?;
605 
606         Ok(())
607     }
608 
609     fn put_string(
610         &self,
611         vc_data: &VirtualConsoleData,
612         data: &[u16],
613         mut count: u32,
614         y: u32,
615         x: u32,
616         fg: u32,
617         bg: u32,
618     ) -> Result<(), SystemError> {
619         // 向上取整
620         let width = (vc_data.font.width + 7) / 8;
621         let cellsize = width * vc_data.font.height;
622         let fb_info = self.fb();
623         // 一次能输出的最大字数,避免帧缓冲区溢出
624         let max_cnt = (fb_info.current_fb_var().xres * fb_info.current_fb_var().yres) / cellsize;
625         let attr = FbConAttr::get_attr(data[0], fb_info.color_depth());
626 
627         let mut image = FbImage {
628             x: x * vc_data.font.width,
629             y: y * vc_data.font.height,
630             width: 0,
631             height: vc_data.font.height,
632             fg,
633             bg,
634             depth: 1,
635             data: Default::default(),
636         };
637 
638         image.data.resize(cellsize as usize * count as usize, 0);
639 
640         while count > 0 {
641             let cnt = count.min(max_cnt);
642 
643             image.width = vc_data.font.width * cnt;
644 
645             self.bit_put_string(vc_data, data, attr, cnt, cellsize, &mut image);
646 
647             image.x += cnt * vc_data.font.width;
648             count -= cnt;
649         }
650 
651         Ok(())
652     }
653 
654     fn fbcon_data(&self) -> SpinLockGuard<super::FrameBufferConsoleData> {
655         self.fbcon_data.lock()
656     }
657 
658     fn cursor(&self, vc_data: &VirtualConsoleData, op: CursorOperation, fg: u32, bg: u32) {
659         let mut fbcon_data = self.fbcon_data();
660         let fb_info = self.fb();
661         let mut cursor = FbCursor::default();
662         let charmask = if vc_data.hi_font_mask != 0 {
663             0x1ff
664         } else {
665             0xff
666         };
667 
668         // 向上取整
669         let w = (vc_data.font.width + 7) / 8;
670         let y = fbcon_data.display.real_y(vc_data.state.y as u32);
671 
672         let c = vc_data.screen_buf[vc_data.pos];
673         let attr = FbConAttr::get_attr(c, fb_info.color_depth());
674         let char_offset = (c as usize & charmask) * ((w * vc_data.font.height) as usize);
675 
676         if fbcon_data.cursor_state.image.data != vc_data.font.data[char_offset..]
677             || fbcon_data.cursor_reset
678         {
679             fbcon_data.cursor_state.image.data = vc_data.font.data[char_offset..].to_vec();
680             cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETIMAGE);
681         }
682 
683         if !attr.is_empty() {
684             fbcon_data
685                 .cursor_data
686                 .resize(w as usize * vc_data.font.height as usize, 0);
687 
688             attr.update_attr(
689                 &mut fbcon_data.cursor_data,
690                 &vc_data.font.data[char_offset..],
691                 vc_data,
692             );
693         }
694 
695         if fbcon_data.cursor_state.image.fg != fg
696             || fbcon_data.cursor_state.image.bg != bg
697             || fbcon_data.cursor_reset
698         {
699             fbcon_data.cursor_state.image.fg = fg;
700             fbcon_data.cursor_state.image.bg = bg;
701             cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETCMAP);
702         }
703 
704         if fbcon_data.cursor_state.image.x != (vc_data.font.width * vc_data.state.x as u32)
705             || fbcon_data.cursor_state.image.y != (vc_data.font.height * y)
706             || fbcon_data.cursor_reset
707         {
708             fbcon_data.cursor_state.image.x = vc_data.font.width * vc_data.state.x as u32;
709             fbcon_data.cursor_state.image.y = vc_data.font.height * y;
710             cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETPOS);
711         }
712 
713         if fbcon_data.cursor_state.image.height != vc_data.font.height
714             || fbcon_data.cursor_state.image.width != vc_data.font.width
715             || fbcon_data.cursor_reset
716         {
717             fbcon_data.cursor_state.image.height = vc_data.font.height;
718             fbcon_data.cursor_state.image.width = vc_data.font.width;
719             cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETSIZE);
720         }
721 
722         if fbcon_data.cursor_state.hot_x > 0
723             || fbcon_data.cursor_state.hot_y > 0
724             || fbcon_data.cursor_reset
725         {
726             fbcon_data.cursor_state.hot_x = 0;
727             cursor.hot_y = 0;
728             cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETHOT);
729         }
730 
731         if cursor.set_mode.contains(FbCursorSetMode::FB_CUR_SETSIZE)
732             || vc_data.cursor_type != fbcon_data.display.cursor_shape
733             || fbcon_data.cursor_state.mask.is_empty()
734             || fbcon_data.cursor_reset
735         {
736             fbcon_data.display.cursor_shape = vc_data.cursor_type;
737             cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETSHAPE);
738 
739             let cur_height;
740             match fbcon_data.display.cursor_shape.cursor_size() {
741                 VcCursor::CUR_NONE => {
742                     cur_height = 0;
743                 }
744                 VcCursor::CUR_UNDERLINE => {
745                     if vc_data.font.height < 10 {
746                         cur_height = 1;
747                     } else {
748                         cur_height = 2;
749                     }
750                 }
751                 VcCursor::CUR_LOWER_THIRD => {
752                     cur_height = vc_data.font.height / 3;
753                 }
754                 VcCursor::CUR_LOWER_HALF => {
755                     cur_height = vc_data.font.height >> 1;
756                 }
757                 VcCursor::CUR_TWO_THIRDS => {
758                     cur_height = (vc_data.font.height << 1) / 3;
759                 }
760                 _ => {
761                     cur_height = vc_data.font.height;
762                 }
763             }
764 
765             // 表示空白部分
766             let mut size = (vc_data.font.height - cur_height) * w;
767             while size > 0 {
768                 size -= 1;
769                 fbcon_data.cursor_state.mask.push(0x00);
770             }
771             size = cur_height * w;
772             // 表示光标显示部分
773             while size > 0 {
774                 size -= 1;
775                 fbcon_data.cursor_state.mask.push(0xff);
776             }
777         }
778 
779         match op {
780             CursorOperation::Erase => {
781                 fbcon_data.cursor_state.enable = false;
782             }
783             _ => {
784                 fbcon_data.cursor_state.enable = !vc_data.cursor_type.contains(VcCursor::CUR_SW);
785             }
786         }
787 
788         if !attr.is_empty() {
789             cursor.image.data = fbcon_data.cursor_data.clone();
790         } else {
791             cursor.image.data = vc_data.font.data
792                 [char_offset..char_offset + (w as usize * vc_data.font.height as usize)]
793                 .to_vec();
794         }
795         cursor.image.fg = fbcon_data.cursor_state.image.fg;
796         cursor.image.bg = fbcon_data.cursor_state.image.bg;
797         cursor.image.x = fbcon_data.cursor_state.image.x;
798         cursor.image.y = fbcon_data.cursor_state.image.y;
799         cursor.image.height = fbcon_data.cursor_state.image.height;
800         cursor.image.width = fbcon_data.cursor_state.image.width;
801         cursor.hot_x = fbcon_data.cursor_state.hot_x;
802         cursor.hot_y = fbcon_data.cursor_state.hot_y;
803         cursor.mask = fbcon_data.cursor_state.mask.clone();
804         cursor.enable = fbcon_data.cursor_state.enable;
805         cursor.image.depth = 1;
806         cursor.rop = true;
807 
808         if fb_info.fb_cursor(&cursor).is_err() {
809             let _ = fb_info.soft_cursor(cursor);
810         }
811 
812         fbcon_data.cursor_reset = false;
813     }
814 }
815