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, 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_data: &mut VirtualConsoleData, 178 init: bool, 179 ) -> Result<(), system_error::SystemError> { 180 let fb_set_guard = FRAME_BUFFER_SET.read(); 181 let fb = fb_set_guard.get(vc_data.index); 182 if fb.is_none() { 183 return Err(SystemError::EINVAL); 184 } 185 let fb = fb.unwrap(); 186 if fb.is_none() { 187 panic!( 188 "The Framebuffer with FbID {} has not been initialized yet.", 189 vc_data.index 190 ) 191 } 192 193 let fb = fb.as_ref().unwrap().clone(); 194 195 if init { 196 // 初始化字体 197 let var = fb.current_fb_var(); 198 let font = FontDesc::get_default_font(var.xres, var.yres, 0, 0); 199 vc_data.font.data = font.data.to_vec(); 200 vc_data.font.width = font.width; 201 vc_data.font.height = font.height; 202 vc_data.font.count = font.char_count; 203 } else { 204 warn!("The frontend Framebuffer is not implemented"); 205 } 206 207 vc_data.color_mode = fb.color_depth() != 1; 208 vc_data.complement_mask = if vc_data.color_mode { 0x7700 } else { 0x0800 }; 209 210 if vc_data.font.count == 256 { 211 // ascii 212 vc_data.hi_font_mask = 0; 213 } else { 214 vc_data.hi_font_mask = 0x100; 215 if vc_data.color_mode { 216 vc_data.complement_mask <<= 1; 217 } 218 } 219 220 // TODO: 考虑rotate 221 if init { 222 vc_data.cols = (fb.current_fb_var().xres / vc_data.font.width) as usize; 223 vc_data.rows = (fb.current_fb_var().yres / vc_data.font.height) as usize; 224 225 vc_data.pos = vc_data.state.x + vc_data.state.y * vc_data.cols; 226 227 let new_size = vc_data.cols * vc_data.rows; 228 vc_data.screen_buf.resize(new_size, 0); 229 } else { 230 unimplemented!("Resize is not supported at the moment!"); 231 } 232 233 // 初始化fb 234 *self.fb.lock() = Some(fb); 235 236 Ok(()) 237 } 238 239 fn con_deinit(&self) -> Result<(), system_error::SystemError> { 240 todo!() 241 } 242 243 fn con_clear( 244 &self, 245 vc_data: &mut VirtualConsoleData, 246 sy: usize, 247 sx: usize, 248 height: usize, 249 width: usize, 250 ) -> Result<(), system_error::SystemError> { 251 let fb_data = self.fbcon_data(); 252 253 if height == 0 || width == 0 { 254 return Ok(()); 255 } 256 257 let y_break = (fb_data.display.virt_rows - fb_data.display.yscroll) as usize; 258 if sy < y_break && sy + height > y_break { 259 // 分两次clear 260 let b = y_break - sy; 261 let _ = self.clear( 262 vc_data, 263 fb_data.display.real_y(sy as u32), 264 sx as u32, 265 b as u32, 266 width as u32, 267 ); 268 let _ = self.clear( 269 vc_data, 270 fb_data.display.real_y((sy + b) as u32), 271 sx as u32, 272 (height - b) as u32, 273 width as u32, 274 ); 275 } else { 276 let _ = self.clear( 277 vc_data, 278 fb_data.display.real_y(sy as u32), 279 sx as u32, 280 height as u32, 281 width as u32, 282 ); 283 } 284 285 Ok(()) 286 } 287 288 fn con_putc( 289 &self, 290 vc_data: &VirtualConsoleData, 291 ch: u16, 292 xpos: u32, 293 ypos: u32, 294 ) -> Result<(), system_error::SystemError> { 295 self.con_putcs(vc_data, &[ch], 1, ypos, xpos) 296 } 297 298 fn con_putcs( 299 &self, 300 vc_data: &VirtualConsoleData, 301 buf: &[u16], 302 count: usize, 303 ypos: u32, 304 xpos: u32, 305 ) -> Result<(), SystemError> { 306 if count == 0 { 307 return Ok(()); 308 } 309 let fbcon_data = self.fbcon_data(); 310 let c = buf[0]; 311 self.put_string( 312 vc_data, 313 buf, 314 count as u32, 315 fbcon_data.display.real_y(ypos), 316 xpos, 317 self.get_color(vc_data, c, true), 318 self.get_color(vc_data, c, false), 319 ) 320 } 321 322 fn con_getxy( 323 &self, 324 vc_data: &VirtualConsoleData, 325 pos: usize, 326 ) -> Result<(usize, usize, usize), SystemError> { 327 if pos < vc_data.screen_buf.len() { 328 let x = pos % vc_data.cols; 329 let y = pos / vc_data.cols; 330 let mut next_line_start = pos + (vc_data.cols - x); 331 if next_line_start >= vc_data.screen_buf.len() { 332 next_line_start = 0 333 } 334 return Ok((next_line_start, x, y)); 335 } else { 336 return Ok((0, 0, 0)); 337 } 338 } 339 340 #[allow(clippy::if_same_then_else)] 341 fn con_cursor( 342 &self, 343 vc_data: &VirtualConsoleData, 344 op: crate::driver::tty::virtual_terminal::virtual_console::CursorOperation, 345 ) { 346 let mut fbcon_data = self.fbcon_data(); 347 348 let c = vc_data.screen_buf[vc_data.pos]; 349 350 if vc_data.cursor_type.contains(VcCursor::CUR_SW) { 351 // 取消硬光标Timer,但是现在没有硬光标,先写在这 352 } else { 353 // 添加硬光标Timer 354 } 355 356 fbcon_data.cursor_flash = op != CursorOperation::Erase; 357 358 drop(fbcon_data); 359 360 self.cursor( 361 vc_data, 362 op, 363 self.get_color(vc_data, c, true), 364 self.get_color(vc_data, c, false), 365 ); 366 } 367 368 fn con_set_palette( 369 &self, 370 vc_data: &VirtualConsoleData, 371 color_table: &[u8], 372 ) -> Result<(), SystemError> { 373 let fb_info = self.fb(); 374 let depth = fb_info.color_depth(); 375 let mut palette = Vec::new(); 376 palette.resize(16, Color::default()); 377 if depth > 3 { 378 let vc_palette = &vc_data.palette; 379 for i in 0..16 { 380 let idx = color_table[i]; 381 let col = palette.get_mut(idx as usize).unwrap(); 382 col.red = (vc_palette[i].red << 8) | vc_palette[i].red; 383 col.green = (vc_palette[i].green << 8) | vc_palette[i].green; 384 col.blue = (vc_palette[i].blue << 8) | vc_palette[i].blue; 385 } 386 } else { 387 todo!() 388 } 389 390 self.fb().set_color_map(palette)?; 391 392 Ok(()) 393 } 394 395 #[inline(never)] 396 fn con_scroll( 397 &self, 398 vc_data: &mut VirtualConsoleData, 399 top: usize, 400 bottom: usize, 401 dir: crate::driver::tty::virtual_terminal::virtual_console::ScrollDir, 402 mut count: usize, 403 ) -> bool { 404 self.con_cursor(vc_data, CursorOperation::Erase); 405 406 let fbcon_data = self.fbcon_data(); 407 let scroll_mode = fbcon_data.display.scroll_mode; 408 409 drop(fbcon_data); 410 411 match dir { 412 ScrollDir::Up => { 413 if count > vc_data.rows { 414 count = vc_data.rows; 415 } 416 417 match scroll_mode { 418 ScrollMode::Move => { 419 let start = top * vc_data.cols; 420 let end = bottom * vc_data.cols; 421 vc_data.screen_buf[start..end].rotate_left(count * vc_data.cols); 422 423 let _ = self.bmove( 424 vc_data, 425 top as i32, 426 0, 427 top as i32 - count as i32, 428 0, 429 (bottom - top) as u32, 430 vc_data.cols as u32, 431 ); 432 433 let _ = self.con_clear(vc_data, bottom - count, 0, count, vc_data.cols); 434 435 let offset = vc_data.cols * (bottom - count); 436 for i in 437 vc_data.screen_buf[offset..(offset + (vc_data.cols * count))].iter_mut() 438 { 439 *i = vc_data.erase_char; 440 } 441 442 return true; 443 } 444 ScrollMode::PanMove => todo!(), 445 ScrollMode::WrapMove => todo!(), 446 ScrollMode::Redraw => { 447 let start = top * vc_data.cols; 448 let end = bottom * vc_data.cols; 449 vc_data.screen_buf[start..end].rotate_left(count * vc_data.cols); 450 451 let data = &vc_data.screen_buf[start..(bottom - count) * vc_data.cols]; 452 453 for line in top..(bottom - count) { 454 let mut start = line * vc_data.cols; 455 let end = start + vc_data.cols; 456 let mut offset = start; 457 let mut attr = 1; 458 let mut x = 0; 459 while offset < end { 460 let c = data[offset]; 461 462 if attr != c & 0xff00 { 463 // 属性变化,输出完上一个的并且更新属性 464 attr = c & 0xff00; 465 466 let count = offset - start; 467 let _ = self.con_putcs( 468 vc_data, 469 &data[start..offset], 470 count, 471 line as u32, 472 x, 473 ); 474 start = offset; 475 x += count as u32; 476 } 477 478 offset += 1; 479 } 480 let _ = self.con_putcs( 481 vc_data, 482 &data[start..offset], 483 offset - start, 484 line as u32, 485 x, 486 ); 487 } 488 489 let _ = self.con_clear(vc_data, bottom - count, 0, count, vc_data.cols); 490 491 let offset = vc_data.cols * (bottom - count); 492 for i in 493 vc_data.screen_buf[offset..(offset + (vc_data.cols * count))].iter_mut() 494 { 495 *i = vc_data.erase_char; 496 } 497 498 return true; 499 } 500 ScrollMode::PanRedraw => todo!(), 501 } 502 } 503 ScrollDir::Down => { 504 if count > vc_data.rows { 505 count = vc_data.rows; 506 } 507 508 match scroll_mode { 509 ScrollMode::Move => { 510 let start = top * vc_data.cols; 511 let end = bottom * vc_data.cols; 512 vc_data.screen_buf[start..end].rotate_right(count * vc_data.cols); 513 514 let _ = self.bmove( 515 vc_data, 516 top as i32, 517 0, 518 top as i32 + count as i32, 519 0, 520 (bottom - top - count) as u32, 521 vc_data.cols as u32, 522 ); 523 524 let _ = self.con_clear(vc_data, top, 0, count, vc_data.cols); 525 526 let offset = vc_data.cols * count; 527 for i in vc_data.screen_buf[start..(start + offset)].iter_mut() { 528 *i = vc_data.erase_char; 529 } 530 531 return true; 532 } 533 ScrollMode::PanMove => todo!(), 534 ScrollMode::WrapMove => todo!(), 535 ScrollMode::Redraw => { 536 // self.scroll_redraw( 537 // vc_data, 538 // bottom - 1, 539 // bottom - top - count, 540 // count * vc_data.cols, 541 // false, 542 // ); 543 544 let _ = self.con_clear(vc_data, top, 0, count, vc_data.cols); 545 546 let offset = vc_data.cols * top; 547 for i in 548 vc_data.screen_buf[offset..(offset + (vc_data.cols * count))].iter_mut() 549 { 550 *i = vc_data.erase_char; 551 } 552 553 return true; 554 } 555 ScrollMode::PanRedraw => todo!(), 556 } 557 } 558 } 559 } 560 } 561 562 impl FrameBufferConsole for BlittingFbConsole { 563 fn bmove( 564 &self, 565 vc_data: &VirtualConsoleData, 566 sy: i32, 567 sx: i32, 568 dy: i32, 569 dx: i32, 570 height: u32, 571 width: u32, 572 ) -> Result<(), SystemError> { 573 let area = CopyAreaData::new( 574 dx * vc_data.font.width as i32, 575 dy * vc_data.font.height as i32, 576 width * vc_data.font.width, 577 height * vc_data.font.height, 578 sx * vc_data.font.width as i32, 579 sy * vc_data.font.height as i32, 580 ); 581 582 self.fb().fb_copyarea(area); 583 Ok(()) 584 } 585 586 fn clear( 587 &self, 588 vc_data: &VirtualConsoleData, 589 sy: u32, 590 sx: u32, 591 height: u32, 592 width: u32, 593 ) -> Result<(), SystemError> { 594 let region = FillRectData::new( 595 sx * vc_data.font.width, 596 sy * vc_data.font.height, 597 width * vc_data.font.width, 598 height * vc_data.font.height, 599 self.get_color(vc_data, vc_data.erase_char, false), 600 FillRectROP::Copy, 601 ); 602 603 self.fb().fb_fillrect(region)?; 604 605 Ok(()) 606 } 607 608 fn put_string( 609 &self, 610 vc_data: &VirtualConsoleData, 611 data: &[u16], 612 mut count: u32, 613 y: u32, 614 x: u32, 615 fg: u32, 616 bg: u32, 617 ) -> Result<(), SystemError> { 618 // 向上取整 619 let width = (vc_data.font.width + 7) / 8; 620 let cellsize = width * vc_data.font.height; 621 let fb_info = self.fb(); 622 // 一次能输出的最大字数,避免帧缓冲区溢出 623 let max_cnt = (fb_info.current_fb_var().xres * fb_info.current_fb_var().yres) / cellsize; 624 let attr = FbConAttr::get_attr(data[0], fb_info.color_depth()); 625 626 let mut image = FbImage { 627 x: x * vc_data.font.width, 628 y: y * vc_data.font.height, 629 width: 0, 630 height: vc_data.font.height, 631 fg, 632 bg, 633 depth: 1, 634 data: Default::default(), 635 }; 636 637 image.data.resize(cellsize as usize * count as usize, 0); 638 639 while count > 0 { 640 let cnt = count.min(max_cnt); 641 642 image.width = vc_data.font.width * cnt; 643 644 self.bit_put_string(vc_data, data, attr, cnt, cellsize, &mut image); 645 646 image.x += cnt * vc_data.font.width; 647 count -= cnt; 648 } 649 650 Ok(()) 651 } 652 653 fn fbcon_data(&self) -> SpinLockGuard<super::FrameBufferConsoleData> { 654 self.fbcon_data.lock() 655 } 656 657 fn cursor(&self, vc_data: &VirtualConsoleData, op: CursorOperation, fg: u32, bg: u32) { 658 let mut fbcon_data = self.fbcon_data(); 659 let fb_info = self.fb(); 660 let mut cursor = FbCursor::default(); 661 let charmask = if vc_data.hi_font_mask != 0 { 662 0x1ff 663 } else { 664 0xff 665 }; 666 667 // 向上取整 668 let w = (vc_data.font.width + 7) / 8; 669 let y = fbcon_data.display.real_y(vc_data.state.y as u32); 670 671 let c = vc_data.screen_buf[vc_data.pos]; 672 let attr = FbConAttr::get_attr(c, fb_info.color_depth()); 673 let char_offset = (c as usize & charmask) * ((w * vc_data.font.height) as usize); 674 675 if fbcon_data.cursor_state.image.data != vc_data.font.data[char_offset..] 676 || fbcon_data.cursor_reset 677 { 678 fbcon_data.cursor_state.image.data = vc_data.font.data[char_offset..].to_vec(); 679 cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETIMAGE); 680 } 681 682 if !attr.is_empty() { 683 fbcon_data 684 .cursor_data 685 .resize(w as usize * vc_data.font.height as usize, 0); 686 687 attr.update_attr( 688 &mut fbcon_data.cursor_data, 689 &vc_data.font.data[char_offset..], 690 vc_data, 691 ); 692 } 693 694 if fbcon_data.cursor_state.image.fg != fg 695 || fbcon_data.cursor_state.image.bg != bg 696 || fbcon_data.cursor_reset 697 { 698 fbcon_data.cursor_state.image.fg = fg; 699 fbcon_data.cursor_state.image.bg = bg; 700 cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETCMAP); 701 } 702 703 if fbcon_data.cursor_state.image.x != (vc_data.font.width * vc_data.state.x as u32) 704 || fbcon_data.cursor_state.image.y != (vc_data.font.height * y) 705 || fbcon_data.cursor_reset 706 { 707 fbcon_data.cursor_state.image.x = vc_data.font.width * vc_data.state.x as u32; 708 fbcon_data.cursor_state.image.y = vc_data.font.height * y; 709 cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETPOS); 710 } 711 712 if fbcon_data.cursor_state.image.height != vc_data.font.height 713 || fbcon_data.cursor_state.image.width != vc_data.font.width 714 || fbcon_data.cursor_reset 715 { 716 fbcon_data.cursor_state.image.height = vc_data.font.height; 717 fbcon_data.cursor_state.image.width = vc_data.font.width; 718 cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETSIZE); 719 } 720 721 if fbcon_data.cursor_state.hot_x > 0 722 || fbcon_data.cursor_state.hot_y > 0 723 || fbcon_data.cursor_reset 724 { 725 fbcon_data.cursor_state.hot_x = 0; 726 cursor.hot_y = 0; 727 cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETHOT); 728 } 729 730 if cursor.set_mode.contains(FbCursorSetMode::FB_CUR_SETSIZE) 731 || vc_data.cursor_type != fbcon_data.display.cursor_shape 732 || fbcon_data.cursor_state.mask.is_empty() 733 || fbcon_data.cursor_reset 734 { 735 fbcon_data.display.cursor_shape = vc_data.cursor_type; 736 cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETSHAPE); 737 738 let cur_height; 739 match fbcon_data.display.cursor_shape.cursor_size() { 740 VcCursor::CUR_NONE => { 741 cur_height = 0; 742 } 743 VcCursor::CUR_UNDERLINE => { 744 if vc_data.font.height < 10 { 745 cur_height = 1; 746 } else { 747 cur_height = 2; 748 } 749 } 750 VcCursor::CUR_LOWER_THIRD => { 751 cur_height = vc_data.font.height / 3; 752 } 753 VcCursor::CUR_LOWER_HALF => { 754 cur_height = vc_data.font.height >> 1; 755 } 756 VcCursor::CUR_TWO_THIRDS => { 757 cur_height = (vc_data.font.height << 1) / 3; 758 } 759 _ => { 760 cur_height = vc_data.font.height; 761 } 762 } 763 764 // 表示空白部分 765 let mut size = (vc_data.font.height - cur_height) * w; 766 while size > 0 { 767 size -= 1; 768 fbcon_data.cursor_state.mask.push(0x00); 769 } 770 size = cur_height * w; 771 // 表示光标显示部分 772 while size > 0 { 773 size -= 1; 774 fbcon_data.cursor_state.mask.push(0xff); 775 } 776 } 777 778 match op { 779 CursorOperation::Erase => { 780 fbcon_data.cursor_state.enable = false; 781 } 782 _ => { 783 fbcon_data.cursor_state.enable = !vc_data.cursor_type.contains(VcCursor::CUR_SW); 784 } 785 } 786 787 if !attr.is_empty() { 788 cursor.image.data = fbcon_data.cursor_data.clone(); 789 } else { 790 cursor.image.data = vc_data.font.data 791 [char_offset..char_offset + (w as usize * vc_data.font.height as usize)] 792 .to_vec(); 793 } 794 cursor.image.fg = fbcon_data.cursor_state.image.fg; 795 cursor.image.bg = fbcon_data.cursor_state.image.bg; 796 cursor.image.x = fbcon_data.cursor_state.image.x; 797 cursor.image.y = fbcon_data.cursor_state.image.y; 798 cursor.image.height = fbcon_data.cursor_state.image.height; 799 cursor.image.width = fbcon_data.cursor_state.image.width; 800 cursor.hot_x = fbcon_data.cursor_state.hot_x; 801 cursor.hot_y = fbcon_data.cursor_state.hot_y; 802 cursor.mask = fbcon_data.cursor_state.mask.clone(); 803 cursor.enable = fbcon_data.cursor_state.enable; 804 cursor.image.depth = 1; 805 cursor.rop = true; 806 807 if fb_info.fb_cursor(&cursor).is_err() { 808 let _ = fb_info.soft_cursor(cursor); 809 } 810 811 fbcon_data.cursor_reset = false; 812 } 813 } 814