1 /* $NetBSD: rasops.c,v 1.73 2015/04/18 11:23:58 mlelstv Exp $ */ 2 3 /*- 4 * Copyright (c) 1999 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: rasops.c,v 1.73 2015/04/18 11:23:58 mlelstv Exp $"); 34 35 #include "opt_rasops.h" 36 #include "rasops_glue.h" 37 #include "opt_wsmsgattrs.h" 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/time.h> 42 #include <sys/kmem.h> 43 44 #include <sys/bswap.h> 45 #include <machine/endian.h> 46 47 #include <dev/wscons/wsdisplayvar.h> 48 #include <dev/wscons/wsconsio.h> 49 #include <dev/wsfont/wsfont.h> 50 #include <dev/rasops/rasops.h> 51 52 #ifndef _KERNEL 53 #include <errno.h> 54 #endif 55 56 #ifdef RASOPS_DEBUG 57 #define DPRINTF aprint_error 58 #else 59 #define DPRINTF while (0) printf 60 #endif 61 62 struct rasops_matchdata { 63 struct rasops_info *ri; 64 int wantcols, wantrows; 65 int bestscore; 66 struct wsdisplay_font *pick; 67 int ident; 68 }; 69 70 /* ANSI colormap (R,G,B). Upper 8 are high-intensity */ 71 const u_char rasops_cmap[256*3] = { 72 0x00, 0x00, 0x00, /* black */ 73 0x7f, 0x00, 0x00, /* red */ 74 0x00, 0x7f, 0x00, /* green */ 75 0x7f, 0x7f, 0x00, /* brown */ 76 0x00, 0x00, 0x7f, /* blue */ 77 0x7f, 0x00, 0x7f, /* magenta */ 78 0x00, 0x7f, 0x7f, /* cyan */ 79 0xc7, 0xc7, 0xc7, /* white - XXX too dim? */ 80 81 0x7f, 0x7f, 0x7f, /* black */ 82 0xff, 0x00, 0x00, /* red */ 83 0x00, 0xff, 0x00, /* green */ 84 0xff, 0xff, 0x00, /* brown */ 85 0x00, 0x00, 0xff, /* blue */ 86 0xff, 0x00, 0xff, /* magenta */ 87 0x00, 0xff, 0xff, /* cyan */ 88 0xff, 0xff, 0xff, /* white */ 89 90 /* 91 * For the cursor, we need at least the last (255th) 92 * color to be white. Fill up white completely for 93 * simplicity. 94 */ 95 #define _CMWHITE 0xff, 0xff, 0xff, 96 #define _CMWHITE16 _CMWHITE _CMWHITE _CMWHITE _CMWHITE \ 97 _CMWHITE _CMWHITE _CMWHITE _CMWHITE \ 98 _CMWHITE _CMWHITE _CMWHITE _CMWHITE \ 99 _CMWHITE _CMWHITE _CMWHITE _CMWHITE 100 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 101 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 102 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 /* but not the last one */ 103 #undef _CMWHITE16 104 #undef _CMWHITE 105 106 /* 107 * For the cursor the fg/bg indices are bit inverted, so 108 * provide complimentary colors in the upper 16 entries. 109 */ 110 0x7f, 0x7f, 0x7f, /* black */ 111 0xff, 0x00, 0x00, /* red */ 112 0x00, 0xff, 0x00, /* green */ 113 0xff, 0xff, 0x00, /* brown */ 114 0x00, 0x00, 0xff, /* blue */ 115 0xff, 0x00, 0xff, /* magenta */ 116 0x00, 0xff, 0xff, /* cyan */ 117 0xff, 0xff, 0xff, /* white */ 118 119 0x00, 0x00, 0x00, /* black */ 120 0x7f, 0x00, 0x00, /* red */ 121 0x00, 0x7f, 0x00, /* green */ 122 0x7f, 0x7f, 0x00, /* brown */ 123 0x00, 0x00, 0x7f, /* blue */ 124 0x7f, 0x00, 0x7f, /* magenta */ 125 0x00, 0x7f, 0x7f, /* cyan */ 126 0xc7, 0xc7, 0xc7, /* white - XXX too dim? */ 127 }; 128 129 /* True if color is gray */ 130 const u_char rasops_isgray[16] = { 131 1, 0, 0, 0, 132 0, 0, 0, 1, 133 1, 0, 0, 0, 134 0, 0, 0, 1 135 }; 136 137 /* Generic functions */ 138 static void rasops_copyrows(void *, int, int, int); 139 static int rasops_mapchar(void *, int, u_int *); 140 static void rasops_cursor(void *, int, int, int); 141 static int rasops_allocattr_color(void *, int, int, int, long *); 142 static int rasops_allocattr_mono(void *, int, int, int, long *); 143 static void rasops_do_cursor(struct rasops_info *); 144 static void rasops_init_devcmap(struct rasops_info *); 145 146 #if NRASOPS_ROTATION > 0 147 static void rasops_rotate_font(int *, int); 148 static void rasops_copychar(void *, int, int, int, int); 149 150 /* rotate clockwise */ 151 static void rasops_copycols_rotated_cw(void *, int, int, int, int); 152 static void rasops_copyrows_rotated_cw(void *, int, int, int); 153 static void rasops_erasecols_rotated_cw(void *, int, int, int, long); 154 static void rasops_eraserows_rotated_cw(void *, int, int, long); 155 static void rasops_putchar_rotated_cw(void *, int, int, u_int, long); 156 157 /* rotate counter-clockwise */ 158 static void rasops_copychar_ccw(void *, int, int, int, int); 159 static void rasops_copycols_rotated_ccw(void *, int, int, int, int); 160 static void rasops_copyrows_rotated_ccw(void *, int, int, int); 161 #define rasops_erasecols_rotated_ccw rasops_erasecols_rotated_cw 162 #define rasops_eraserows_rotated_ccw rasops_eraserows_rotated_cw 163 static void rasops_putchar_rotated_ccw(void *, int, int, u_int, long); 164 165 /* 166 * List of all rotated fonts 167 */ 168 SLIST_HEAD(, rotatedfont) rotatedfonts = SLIST_HEAD_INITIALIZER(rotatedfonts); 169 struct rotatedfont { 170 SLIST_ENTRY(rotatedfont) rf_next; 171 int rf_cookie; 172 int rf_rotated; 173 }; 174 #endif /* NRASOPS_ROTATION > 0 */ 175 176 void rasops_make_box_chars_8(struct rasops_info *); 177 void rasops_make_box_chars_16(struct rasops_info *); 178 void rasops_make_box_chars_32(struct rasops_info *); 179 void rasops_make_box_chars_alpha(struct rasops_info *); 180 181 extern int cold; 182 183 /* 184 * Initialize a 'rasops_info' descriptor. 185 */ 186 int 187 rasops_init(struct rasops_info *ri, int wantrows, int wantcols) 188 { 189 190 memset (&ri->ri_optfont, 0, sizeof(ri->ri_optfont)); 191 #ifdef _KERNEL 192 /* Select a font if the caller doesn't care */ 193 if (ri->ri_font == NULL) { 194 int cookie = -1; 195 int flags; 196 197 wsfont_init(); 198 199 /* 200 * first, try to find something that's as close as possible 201 * to the caller's requested terminal size 202 */ 203 if (wantrows == 0) 204 wantrows = RASOPS_DEFAULT_HEIGHT; 205 if (wantcols == 0) 206 wantcols = RASOPS_DEFAULT_WIDTH; 207 208 flags = WSFONT_FIND_BESTWIDTH | WSFONT_FIND_BITMAP; 209 if ((ri->ri_flg & RI_ENABLE_ALPHA) != 0) 210 flags |= WSFONT_FIND_ALPHA; 211 212 cookie = wsfont_find(NULL, 213 ri->ri_width / wantcols, 214 0, 215 0, 216 WSDISPLAY_FONTORDER_L2R, 217 WSDISPLAY_FONTORDER_L2R, 218 flags); 219 220 /* 221 * this means there is no supported font in the list 222 */ 223 if (cookie <= 0) { 224 aprint_error("rasops_init: font table is empty\n"); 225 return (-1); 226 } 227 228 #if NRASOPS_ROTATION > 0 229 /* 230 * Pick the rotated version of this font. This will create it 231 * if necessary. 232 */ 233 if (ri->ri_flg & RI_ROTATE_MASK) { 234 if (ri->ri_flg & RI_ROTATE_CW) 235 rasops_rotate_font(&cookie, WSFONT_ROTATE_CW); 236 else if (ri->ri_flg & RI_ROTATE_CCW) 237 rasops_rotate_font(&cookie, WSFONT_ROTATE_CCW); 238 } 239 #endif 240 241 if (wsfont_lock(cookie, &ri->ri_font)) { 242 aprint_error("rasops_init: couldn't lock font\n"); 243 return (-1); 244 } 245 246 ri->ri_wsfcookie = cookie; 247 } 248 #endif 249 250 /* This should never happen in reality... */ 251 #ifdef DEBUG 252 if ((long)ri->ri_bits & 3) { 253 aprint_error("rasops_init: bits not aligned on 32-bit boundary\n"); 254 return (-1); 255 } 256 257 if ((int)ri->ri_stride & 3) { 258 aprint_error("rasops_init: stride not aligned on 32-bit boundary\n"); 259 return (-1); 260 } 261 #endif 262 263 if (rasops_reconfig(ri, wantrows, wantcols)) 264 return (-1); 265 266 rasops_init_devcmap(ri); 267 return (0); 268 } 269 270 /* 271 * Reconfigure (because parameters have changed in some way). 272 */ 273 int 274 rasops_reconfig(struct rasops_info *ri, int wantrows, int wantcols) 275 { 276 int bpp, s, len; 277 278 s = splhigh(); 279 280 if (wantrows == 0) 281 wantrows = RASOPS_DEFAULT_HEIGHT; 282 if (wantcols == 0) 283 wantcols = RASOPS_DEFAULT_WIDTH; 284 285 /* throw away old line drawing character bitmaps, if we have any */ 286 if (ri->ri_optfont.data != NULL) { 287 kmem_free(ri->ri_optfont.data, ri->ri_optfont.stride * 288 ri->ri_optfont.fontheight * ri->ri_optfont.numchars); 289 ri->ri_optfont.data = NULL; 290 } 291 292 /* autogenerate box drawing characters */ 293 ri->ri_optfont.firstchar = WSFONT_FLAG_OPT; 294 ri->ri_optfont.numchars = 16; 295 ri->ri_optfont.fontwidth = ri->ri_font->fontwidth; 296 ri->ri_optfont.fontheight = ri->ri_font->fontheight; 297 ri->ri_optfont.stride = ri->ri_font->stride; 298 len = ri->ri_optfont.fontheight * ri->ri_optfont.stride * 299 ri->ri_optfont.numchars; 300 301 if (((ri->ri_flg & RI_NO_AUTO) == 0) && 302 ((ri->ri_optfont.data = kmem_zalloc(len, KM_SLEEP)) != NULL)) { 303 304 if (ri->ri_optfont.stride < ri->ri_optfont.fontwidth) { 305 switch (ri->ri_optfont.stride) { 306 case 1: 307 rasops_make_box_chars_8(ri); 308 break; 309 case 2: 310 rasops_make_box_chars_16(ri); 311 break; 312 case 4: 313 rasops_make_box_chars_32(ri); 314 break; 315 } 316 } else { 317 rasops_make_box_chars_alpha(ri); 318 } 319 } else 320 memset(&ri->ri_optfont, 0, sizeof(ri->ri_optfont)); 321 322 if (ri->ri_font->fontwidth > 32 || ri->ri_font->fontwidth < 4) 323 panic("rasops_init: fontwidth assumptions botched!"); 324 325 /* Need this to frob the setup below */ 326 bpp = (ri->ri_depth == 15 ? 16 : ri->ri_depth); 327 328 if ((ri->ri_flg & RI_CFGDONE) != 0) 329 ri->ri_bits = ri->ri_origbits; 330 331 /* Don't care if the caller wants a hideously small console */ 332 if (wantrows < 10) 333 wantrows = 10; 334 335 if (wantcols < 20) 336 wantcols = 20; 337 338 /* Now constrain what they get */ 339 ri->ri_emuwidth = ri->ri_font->fontwidth * wantcols; 340 ri->ri_emuheight = ri->ri_font->fontheight * wantrows; 341 342 if (ri->ri_emuwidth > ri->ri_width) 343 ri->ri_emuwidth = ri->ri_width; 344 345 if (ri->ri_emuheight > ri->ri_height) 346 ri->ri_emuheight = ri->ri_height; 347 348 /* Reduce width until aligned on a 32-bit boundary */ 349 while ((ri->ri_emuwidth * bpp & 31) != 0) 350 ri->ri_emuwidth--; 351 352 #if NRASOPS_ROTATION > 0 353 if (ri->ri_flg & (RI_ROTATE_CW|RI_ROTATE_CCW)) { 354 ri->ri_rows = ri->ri_emuwidth / ri->ri_font->fontwidth; 355 ri->ri_cols = ri->ri_emuheight / ri->ri_font->fontheight; 356 } else 357 #endif 358 { 359 360 ri->ri_cols = ri->ri_emuwidth / ri->ri_font->fontwidth; 361 ri->ri_rows = ri->ri_emuheight / ri->ri_font->fontheight; 362 } 363 ri->ri_emustride = ri->ri_emuwidth * bpp >> 3; 364 ri->ri_delta = ri->ri_stride - ri->ri_emustride; 365 ri->ri_ccol = 0; 366 ri->ri_crow = 0; 367 ri->ri_pelbytes = bpp >> 3; 368 369 ri->ri_xscale = (ri->ri_font->fontwidth * bpp) >> 3; 370 ri->ri_yscale = ri->ri_font->fontheight * ri->ri_stride; 371 ri->ri_fontscale = ri->ri_font->fontheight * ri->ri_font->stride; 372 373 #ifdef DEBUG 374 if ((ri->ri_delta & 3) != 0) 375 panic("rasops_init: ri_delta not aligned on 32-bit boundary"); 376 #endif 377 /* Clear the entire display */ 378 if ((ri->ri_flg & RI_CLEAR) != 0) 379 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height); 380 381 /* Now centre our window if needs be */ 382 ri->ri_origbits = ri->ri_bits; 383 ri->ri_hworigbits = ri->ri_hwbits; 384 385 if ((ri->ri_flg & RI_CENTER) != 0) { 386 ri->ri_bits += (((ri->ri_width * bpp >> 3) - 387 ri->ri_emustride) >> 1) & ~3; 388 ri->ri_bits += ((ri->ri_height - ri->ri_emuheight) >> 1) * 389 ri->ri_stride; 390 if (ri->ri_hwbits != NULL) { 391 ri->ri_hwbits += (((ri->ri_width * bpp >> 3) - 392 ri->ri_emustride) >> 1) & ~3; 393 ri->ri_hwbits += ((ri->ri_height - ri->ri_emuheight) >> 1) * 394 ri->ri_stride; 395 } 396 ri->ri_yorigin = (int)(ri->ri_bits - ri->ri_origbits) 397 / ri->ri_stride; 398 ri->ri_xorigin = (((int)(ri->ri_bits - ri->ri_origbits) 399 % ri->ri_stride) * 8 / bpp); 400 } else 401 ri->ri_xorigin = ri->ri_yorigin = 0; 402 403 /* 404 * Fill in defaults for operations set. XXX this nukes private 405 * routines used by accelerated fb drivers. 406 */ 407 ri->ri_ops.mapchar = rasops_mapchar; 408 ri->ri_ops.copyrows = rasops_copyrows; 409 ri->ri_ops.copycols = rasops_copycols; 410 ri->ri_ops.erasecols = rasops_erasecols; 411 ri->ri_ops.eraserows = rasops_eraserows; 412 ri->ri_ops.cursor = rasops_cursor; 413 ri->ri_do_cursor = rasops_do_cursor; 414 415 if (ri->ri_depth < 8 || (ri->ri_flg & RI_FORCEMONO) != 0) { 416 ri->ri_ops.allocattr = rasops_allocattr_mono; 417 ri->ri_caps = WSSCREEN_UNDERLINE | WSSCREEN_REVERSE; 418 } else { 419 ri->ri_ops.allocattr = rasops_allocattr_color; 420 ri->ri_caps = WSSCREEN_UNDERLINE | WSSCREEN_HILIT | 421 WSSCREEN_WSCOLORS | WSSCREEN_REVERSE; 422 } 423 424 switch (ri->ri_depth) { 425 #if NRASOPS1 > 0 426 case 1: 427 rasops1_init(ri); 428 break; 429 #endif 430 #if NRASOPS2 > 0 431 case 2: 432 rasops2_init(ri); 433 break; 434 #endif 435 #if NRASOPS4 > 0 436 case 4: 437 rasops4_init(ri); 438 break; 439 #endif 440 #if NRASOPS8 > 0 441 case 8: 442 rasops8_init(ri); 443 break; 444 #endif 445 #if NRASOPS15 > 0 || NRASOPS16 > 0 446 case 15: 447 case 16: 448 rasops15_init(ri); 449 break; 450 #endif 451 #if NRASOPS24 > 0 452 case 24: 453 rasops24_init(ri); 454 break; 455 #endif 456 #if NRASOPS32 > 0 457 case 32: 458 rasops32_init(ri); 459 break; 460 #endif 461 default: 462 ri->ri_flg &= ~RI_CFGDONE; 463 splx(s); 464 return (-1); 465 } 466 467 #if NRASOPS_ROTATION > 0 468 if (ri->ri_flg & RI_ROTATE_MASK) { 469 if (ri->ri_flg & RI_ROTATE_CW) { 470 ri->ri_real_ops = ri->ri_ops; 471 ri->ri_ops.copycols = rasops_copycols_rotated_cw; 472 ri->ri_ops.copyrows = rasops_copyrows_rotated_cw; 473 ri->ri_ops.erasecols = rasops_erasecols_rotated_cw; 474 ri->ri_ops.eraserows = rasops_eraserows_rotated_cw; 475 ri->ri_ops.putchar = rasops_putchar_rotated_cw; 476 } else if (ri->ri_flg & RI_ROTATE_CCW) { 477 ri->ri_real_ops = ri->ri_ops; 478 ri->ri_ops.copycols = rasops_copycols_rotated_ccw; 479 ri->ri_ops.copyrows = rasops_copyrows_rotated_ccw; 480 ri->ri_ops.erasecols = rasops_erasecols_rotated_ccw; 481 ri->ri_ops.eraserows = rasops_eraserows_rotated_ccw; 482 ri->ri_ops.putchar = rasops_putchar_rotated_ccw; 483 } 484 } 485 #endif 486 487 ri->ri_flg |= RI_CFGDONE; 488 splx(s); 489 return (0); 490 } 491 492 /* 493 * Map a character. 494 */ 495 static int 496 rasops_mapchar(void *cookie, int c, u_int *cp) 497 { 498 struct rasops_info *ri; 499 500 ri = (struct rasops_info *)cookie; 501 502 #ifdef DIAGNOSTIC 503 if (ri->ri_font == NULL) 504 panic("rasops_mapchar: no font selected"); 505 #endif 506 507 if ( (c = wsfont_map_unichar(ri->ri_font, c)) < 0) { 508 *cp = ' '; 509 return (0); 510 } 511 512 if (c < ri->ri_font->firstchar) { 513 *cp = ' '; 514 return (0); 515 } 516 517 #if 0 518 if (c - ri->ri_font->firstchar >= ri->ri_font->numchars) { 519 *cp = ' '; 520 return (0); 521 } 522 #endif 523 *cp = c; 524 return (5); 525 } 526 527 /* 528 * Allocate a color attribute. 529 */ 530 static int 531 rasops_allocattr_color(void *cookie, int fg, int bg, int flg, 532 long *attr) 533 { 534 int swap; 535 536 if (__predict_false((unsigned int)fg >= sizeof(rasops_isgray) || 537 (unsigned int)bg >= sizeof(rasops_isgray))) 538 return (EINVAL); 539 540 #ifdef RASOPS_CLIPPING 541 fg &= 7; 542 bg &= 7; 543 #endif 544 if ((flg & WSATTR_BLINK) != 0) 545 return (EINVAL); 546 547 if ((flg & WSATTR_WSCOLORS) == 0) { 548 #ifdef WS_DEFAULT_FG 549 fg = WS_DEFAULT_FG; 550 #else 551 fg = WSCOL_WHITE; 552 #endif 553 #ifdef WS_DEFAULT_BG 554 bg = WS_DEFAULT_BG; 555 #else 556 bg = WSCOL_BLACK; 557 #endif 558 } 559 560 if ((flg & WSATTR_REVERSE) != 0) { 561 swap = fg; 562 fg = bg; 563 bg = swap; 564 } 565 566 if ((flg & WSATTR_HILIT) != 0) 567 fg += 8; 568 569 flg = ((flg & WSATTR_UNDERLINE) ? 1 : 0); 570 571 if (rasops_isgray[fg]) 572 flg |= 2; 573 574 if (rasops_isgray[bg]) 575 flg |= 4; 576 577 *attr = (bg << 16) | (fg << 24) | flg; 578 return (0); 579 } 580 581 /* 582 * Allocate a mono attribute. 583 */ 584 static int 585 rasops_allocattr_mono(void *cookie, int fg, int bg, int flg, 586 long *attr) 587 { 588 int swap; 589 590 if ((flg & (WSATTR_BLINK | WSATTR_HILIT | WSATTR_WSCOLORS)) != 0) 591 return (EINVAL); 592 593 fg = 1; 594 bg = 0; 595 596 if ((flg & WSATTR_REVERSE) != 0) { 597 swap = fg; 598 fg = bg; 599 bg = swap; 600 } 601 602 *attr = (bg << 16) | (fg << 24) | ((flg & WSATTR_UNDERLINE) ? 7 : 6); 603 return (0); 604 } 605 606 /* 607 * Copy rows. 608 */ 609 static void 610 rasops_copyrows(void *cookie, int src, int dst, int num) 611 { 612 int32_t *sp, *dp, *hp, *srp, *drp, *hrp; 613 struct rasops_info *ri; 614 int n8, n1, cnt, delta; 615 616 ri = (struct rasops_info *)cookie; 617 hp = hrp = NULL; 618 619 #ifdef RASOPS_CLIPPING 620 if (dst == src) 621 return; 622 623 if (src < 0) { 624 num += src; 625 src = 0; 626 } 627 628 if ((src + num) > ri->ri_rows) 629 num = ri->ri_rows - src; 630 631 if (dst < 0) { 632 num += dst; 633 dst = 0; 634 } 635 636 if ((dst + num) > ri->ri_rows) 637 num = ri->ri_rows - dst; 638 639 if (num <= 0) 640 return; 641 #endif 642 643 num *= ri->ri_font->fontheight; 644 n8 = ri->ri_emustride >> 5; 645 n1 = (ri->ri_emustride >> 2) & 7; 646 647 if (dst < src) { 648 srp = (int32_t *)(ri->ri_bits + src * ri->ri_yscale); 649 drp = (int32_t *)(ri->ri_bits + dst * ri->ri_yscale); 650 if (ri->ri_hwbits) 651 hrp = (int32_t *)(ri->ri_hwbits + dst * 652 ri->ri_yscale); 653 delta = ri->ri_stride; 654 } else { 655 src = ri->ri_font->fontheight * src + num - 1; 656 dst = ri->ri_font->fontheight * dst + num - 1; 657 srp = (int32_t *)(ri->ri_bits + src * ri->ri_stride); 658 drp = (int32_t *)(ri->ri_bits + dst * ri->ri_stride); 659 if (ri->ri_hwbits) 660 hrp = (int32_t *)(ri->ri_hwbits + dst * 661 ri->ri_stride); 662 663 delta = -ri->ri_stride; 664 } 665 666 while (num--) { 667 dp = drp; 668 sp = srp; 669 if (ri->ri_hwbits) 670 hp = hrp; 671 672 DELTA(drp, delta, int32_t *); 673 DELTA(srp, delta, int32_t *); 674 if (ri->ri_hwbits) 675 DELTA(hrp, delta, int32_t *); 676 677 for (cnt = n8; cnt; cnt--) { 678 dp[0] = sp[0]; 679 dp[1] = sp[1]; 680 dp[2] = sp[2]; 681 dp[3] = sp[3]; 682 dp[4] = sp[4]; 683 dp[5] = sp[5]; 684 dp[6] = sp[6]; 685 dp[7] = sp[7]; 686 dp += 8; 687 sp += 8; 688 } 689 if (ri->ri_hwbits) { 690 sp -= (8 * n8); 691 for (cnt = n8; cnt; cnt--) { 692 hp[0] = sp[0]; 693 hp[1] = sp[1]; 694 hp[2] = sp[2]; 695 hp[3] = sp[3]; 696 hp[4] = sp[4]; 697 hp[5] = sp[5]; 698 hp[6] = sp[6]; 699 hp[7] = sp[7]; 700 hp += 8; 701 sp += 8; 702 } 703 } 704 705 for (cnt = n1; cnt; cnt--) { 706 *dp++ = *sp++; 707 if (ri->ri_hwbits) 708 *hp++ = *(sp - 1); 709 } 710 } 711 } 712 713 /* 714 * Copy columns. This is slow, and hard to optimize due to alignment, 715 * and the fact that we have to copy both left->right and right->left. 716 * We simply cop-out here and use memmove(), since it handles all of 717 * these cases anyway. 718 */ 719 void 720 rasops_copycols(void *cookie, int row, int src, int dst, int num) 721 { 722 struct rasops_info *ri; 723 u_char *sp, *dp, *hp; 724 int height; 725 726 ri = (struct rasops_info *)cookie; 727 hp = NULL; 728 729 #ifdef RASOPS_CLIPPING 730 if (dst == src) 731 return; 732 733 /* Catches < 0 case too */ 734 if ((unsigned)row >= (unsigned)ri->ri_rows) 735 return; 736 737 if (src < 0) { 738 num += src; 739 src = 0; 740 } 741 742 if ((src + num) > ri->ri_cols) 743 num = ri->ri_cols - src; 744 745 if (dst < 0) { 746 num += dst; 747 dst = 0; 748 } 749 750 if ((dst + num) > ri->ri_cols) 751 num = ri->ri_cols - dst; 752 753 if (num <= 0) 754 return; 755 #endif 756 757 num *= ri->ri_xscale; 758 row *= ri->ri_yscale; 759 height = ri->ri_font->fontheight; 760 761 sp = ri->ri_bits + row + src * ri->ri_xscale; 762 dp = ri->ri_bits + row + dst * ri->ri_xscale; 763 if (ri->ri_hwbits) 764 hp = ri->ri_hwbits + row + dst * ri->ri_xscale; 765 766 while (height--) { 767 memmove(dp, sp, num); 768 if (ri->ri_hwbits) { 769 memcpy(hp, sp, num); 770 hp += ri->ri_stride; 771 } 772 dp += ri->ri_stride; 773 sp += ri->ri_stride; 774 } 775 } 776 777 /* 778 * Turn cursor off/on. 779 */ 780 static void 781 rasops_cursor(void *cookie, int on, int row, int col) 782 { 783 struct rasops_info *ri; 784 785 ri = (struct rasops_info *)cookie; 786 787 /* Turn old cursor off */ 788 if ((ri->ri_flg & RI_CURSOR) != 0) 789 #ifdef RASOPS_CLIPPING 790 if ((ri->ri_flg & RI_CURSORCLIP) == 0) 791 #endif 792 ri->ri_do_cursor(ri); 793 794 /* Select new cursor */ 795 #ifdef RASOPS_CLIPPING 796 ri->ri_flg &= ~RI_CURSORCLIP; 797 798 if (row < 0 || row >= ri->ri_rows) 799 ri->ri_flg |= RI_CURSORCLIP; 800 else if (col < 0 || col >= ri->ri_cols) 801 ri->ri_flg |= RI_CURSORCLIP; 802 #endif 803 ri->ri_crow = row; 804 ri->ri_ccol = col; 805 806 if (on) { 807 ri->ri_flg |= RI_CURSOR; 808 #ifdef RASOPS_CLIPPING 809 if ((ri->ri_flg & RI_CURSORCLIP) == 0) 810 #endif 811 ri->ri_do_cursor(ri); 812 } else 813 ri->ri_flg &= ~RI_CURSOR; 814 } 815 816 /* 817 * Make the device colormap 818 */ 819 static void 820 rasops_init_devcmap(struct rasops_info *ri) 821 { 822 const u_char *p; 823 int i, c; 824 825 switch (ri->ri_depth) { 826 case 1: 827 ri->ri_devcmap[0] = 0; 828 for (i = 1; i < 16; i++) 829 ri->ri_devcmap[i] = -1; 830 return; 831 832 case 2: 833 for (i = 1; i < 15; i++) 834 ri->ri_devcmap[i] = 0xaaaaaaaa; 835 836 ri->ri_devcmap[0] = 0; 837 ri->ri_devcmap[8] = 0x55555555; 838 ri->ri_devcmap[15] = -1; 839 return; 840 841 case 8: 842 if ((ri->ri_flg & RI_8BIT_IS_RGB) == 0) { 843 for (i = 0; i < 16; i++) 844 ri->ri_devcmap[i] = 845 i | (i<<8) | (i<<16) | (i<<24); 846 return; 847 } 848 } 849 850 p = rasops_cmap; 851 852 for (i = 0; i < 16; i++) { 853 if (ri->ri_rnum <= 8) 854 c = (*p >> (8 - ri->ri_rnum)) << ri->ri_rpos; 855 else 856 c = (*p << (ri->ri_rnum - 8)) << ri->ri_rpos; 857 p++; 858 859 if (ri->ri_gnum <= 8) 860 c |= (*p >> (8 - ri->ri_gnum)) << ri->ri_gpos; 861 else 862 c |= (*p << (ri->ri_gnum - 8)) << ri->ri_gpos; 863 p++; 864 865 if (ri->ri_bnum <= 8) 866 c |= (*p >> (8 - ri->ri_bnum)) << ri->ri_bpos; 867 else 868 c |= (*p << (ri->ri_bnum - 8)) << ri->ri_bpos; 869 p++; 870 871 /* Fill the word for generic routines, which want this */ 872 if (ri->ri_depth == 24) 873 c = c | ((c & 0xff) << 24); 874 else if (ri->ri_depth == 8) { 875 c = c | (c << 8); 876 c |= c << 16; 877 } else if (ri->ri_depth <= 16) 878 c = c | (c << 16); 879 880 /* 24bpp does bswap on the fly. {32,16,15}bpp do it here. */ 881 if ((ri->ri_flg & RI_BSWAP) == 0) 882 ri->ri_devcmap[i] = c; 883 else if (ri->ri_depth == 32) 884 ri->ri_devcmap[i] = bswap32(c); 885 else if (ri->ri_depth == 16 || ri->ri_depth == 15) 886 ri->ri_devcmap[i] = bswap16(c); 887 else 888 ri->ri_devcmap[i] = c; 889 } 890 } 891 892 /* 893 * Unpack a rasops attribute 894 */ 895 void 896 rasops_unpack_attr(long attr, int *fg, int *bg, int *underline) 897 { 898 899 *fg = ((u_int)attr >> 24) & 0xf; 900 *bg = ((u_int)attr >> 16) & 0xf; 901 if (underline != NULL) 902 *underline = (u_int)attr & 1; 903 } 904 905 /* 906 * Erase rows. This isn't static, since 24-bpp uses it in special cases. 907 */ 908 void 909 rasops_eraserows(void *cookie, int row, int num, long attr) 910 { 911 struct rasops_info *ri; 912 int np, nw, cnt, delta; 913 int32_t *dp, *hp, clr; 914 int i; 915 916 ri = (struct rasops_info *)cookie; 917 hp = NULL; 918 919 #ifdef RASOPS_CLIPPING 920 if (row < 0) { 921 num += row; 922 row = 0; 923 } 924 925 if ((row + num) > ri->ri_rows) 926 num = ri->ri_rows - row; 927 928 if (num <= 0) 929 return; 930 #endif 931 932 clr = ri->ri_devcmap[(attr >> 16) & 0xf]; 933 934 /* 935 * XXX The wsdisplay_emulops interface seems a little deficient in 936 * that there is no way to clear the *entire* screen. We provide a 937 * workaround here: if the entire console area is being cleared, and 938 * the RI_FULLCLEAR flag is set, clear the entire display. 939 */ 940 if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR) != 0) { 941 np = ri->ri_stride >> 5; 942 nw = (ri->ri_stride >> 2) & 7; 943 num = ri->ri_height; 944 dp = (int32_t *)ri->ri_origbits; 945 if (ri->ri_hwbits) 946 hp = (int32_t *)ri->ri_hworigbits; 947 delta = 0; 948 } else { 949 np = ri->ri_emustride >> 5; 950 nw = (ri->ri_emustride >> 2) & 7; 951 num *= ri->ri_font->fontheight; 952 dp = (int32_t *)(ri->ri_bits + row * ri->ri_yscale); 953 if (ri->ri_hwbits) 954 hp = (int32_t *)(ri->ri_hwbits + row * 955 ri->ri_yscale); 956 delta = ri->ri_delta; 957 } 958 959 while (num--) { 960 for (cnt = np; cnt; cnt--) { 961 for (i = 0; i < 8; i++) { 962 dp[i] = clr; 963 if (ri->ri_hwbits) 964 hp[i] = clr; 965 } 966 dp += 8; 967 if (ri->ri_hwbits) 968 hp += 8; 969 } 970 971 for (cnt = nw; cnt; cnt--) { 972 *(int32_t *)dp = clr; 973 DELTA(dp, 4, int32_t *); 974 if (ri->ri_hwbits) { 975 *(int32_t *)hp = clr; 976 DELTA(hp, 4, int32_t *); 977 } 978 } 979 980 DELTA(dp, delta, int32_t *); 981 if (ri->ri_hwbits) 982 DELTA(hp, delta, int32_t *); 983 } 984 } 985 986 /* 987 * Actually turn the cursor on or off. This does the dirty work for 988 * rasops_cursor(). 989 */ 990 static void 991 rasops_do_cursor(struct rasops_info *ri) 992 { 993 int full1, height, cnt, slop1, slop2, row, col; 994 u_char *dp, *rp, *hrp, *hp, tmp = 0; 995 996 hrp = hp = NULL; 997 998 #if NRASOPS_ROTATION > 0 999 if (ri->ri_flg & RI_ROTATE_MASK) { 1000 if (ri->ri_flg & RI_ROTATE_CW) { 1001 /* Rotate rows/columns */ 1002 row = ri->ri_ccol; 1003 col = ri->ri_rows - ri->ri_crow - 1; 1004 } else if (ri->ri_flg & RI_ROTATE_CCW) { 1005 /* Rotate rows/columns */ 1006 row = ri->ri_cols - ri->ri_ccol - 1; 1007 col = ri->ri_crow; 1008 } else { /* upside-down */ 1009 row = ri->ri_crow; 1010 col = ri->ri_ccol; 1011 } 1012 } else 1013 #endif 1014 { 1015 row = ri->ri_crow; 1016 col = ri->ri_ccol; 1017 } 1018 1019 rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale; 1020 if (ri->ri_hwbits) 1021 hrp = ri->ri_hwbits + row * ri->ri_yscale + col 1022 * ri->ri_xscale; 1023 height = ri->ri_font->fontheight; 1024 slop1 = (4 - ((long)rp & 3)) & 3; 1025 1026 if (slop1 > ri->ri_xscale) 1027 slop1 = ri->ri_xscale; 1028 1029 slop2 = (ri->ri_xscale - slop1) & 3; 1030 full1 = (ri->ri_xscale - slop1 - slop2) >> 2; 1031 1032 if ((slop1 | slop2) == 0) { 1033 uint32_t tmp32; 1034 /* A common case */ 1035 while (height--) { 1036 dp = rp; 1037 rp += ri->ri_stride; 1038 if (ri->ri_hwbits) { 1039 hp = hrp; 1040 hrp += ri->ri_stride; 1041 } 1042 1043 for (cnt = full1; cnt; cnt--) { 1044 tmp32 = *(int32_t *)dp ^ ~0; 1045 *(int32_t *)dp = tmp32; 1046 dp += 4; 1047 if (ri->ri_hwbits) { 1048 *(int32_t *)hp = tmp32; 1049 hp += 4; 1050 } 1051 } 1052 } 1053 } else { 1054 uint16_t tmp16; 1055 uint32_t tmp32; 1056 /* XXX this is stupid.. use masks instead */ 1057 while (height--) { 1058 dp = rp; 1059 rp += ri->ri_stride; 1060 if (ri->ri_hwbits) { 1061 hp = hrp; 1062 hrp += ri->ri_stride; 1063 } 1064 1065 if (slop1 & 1) { 1066 tmp = *dp ^ ~0; 1067 *dp = tmp; 1068 dp++; 1069 if (ri->ri_hwbits) { 1070 *hp++ = tmp; 1071 } 1072 } 1073 1074 if (slop1 & 2) { 1075 tmp16 = *(int16_t *)dp ^ ~0; 1076 *(uint16_t *)dp = tmp16; 1077 dp += 2; 1078 if (ri->ri_hwbits) { 1079 *(int16_t *)hp = tmp16; 1080 hp += 2; 1081 } 1082 } 1083 1084 for (cnt = full1; cnt; cnt--) { 1085 tmp32 = *(int32_t *)dp ^ ~0; 1086 *(uint32_t *)dp = tmp32; 1087 dp += 4; 1088 if (ri->ri_hwbits) { 1089 *(int32_t *)hp = tmp32; 1090 hp += 4; 1091 } 1092 } 1093 1094 if (slop2 & 1) { 1095 tmp = *dp ^ ~0; 1096 *dp = tmp; 1097 dp++; 1098 if (ri->ri_hwbits) 1099 *hp++ = tmp; 1100 } 1101 1102 if (slop2 & 2) { 1103 tmp16 = *(int16_t *)dp ^ ~0; 1104 *(uint16_t *)dp = tmp16; 1105 if (ri->ri_hwbits) 1106 *(int16_t *)hp = tmp16; 1107 } 1108 } 1109 } 1110 } 1111 1112 /* 1113 * Erase columns. 1114 */ 1115 void 1116 rasops_erasecols(void *cookie, int row, int col, int num, long attr) 1117 { 1118 int n8, height, cnt, slop1, slop2, clr; 1119 struct rasops_info *ri; 1120 int32_t *rp, *dp, *hrp, *hp; 1121 int i; 1122 1123 ri = (struct rasops_info *)cookie; 1124 hrp = hp = NULL; 1125 1126 #ifdef RASOPS_CLIPPING 1127 if ((unsigned)row >= (unsigned)ri->ri_rows) 1128 return; 1129 1130 if (col < 0) { 1131 num += col; 1132 col = 0; 1133 } 1134 1135 if ((col + num) > ri->ri_cols) 1136 num = ri->ri_cols - col; 1137 1138 if (num <= 0) 1139 return; 1140 #endif 1141 1142 num = num * ri->ri_xscale; 1143 rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale); 1144 if (ri->ri_hwbits) 1145 hrp = (int32_t *)(ri->ri_hwbits + row*ri->ri_yscale + 1146 col*ri->ri_xscale); 1147 height = ri->ri_font->fontheight; 1148 clr = ri->ri_devcmap[(attr >> 16) & 0xf]; 1149 1150 /* Don't bother using the full loop for <= 32 pels */ 1151 if (num <= 32) { 1152 if (((num | ri->ri_xscale) & 3) == 0) { 1153 /* Word aligned blt */ 1154 num >>= 2; 1155 1156 while (height--) { 1157 dp = rp; 1158 DELTA(rp, ri->ri_stride, int32_t *); 1159 if (ri->ri_hwbits) { 1160 hp = hrp; 1161 DELTA(hrp, ri->ri_stride, int32_t *); 1162 } 1163 1164 for (cnt = num; cnt; cnt--) { 1165 *dp++ = clr; 1166 if (ri->ri_hwbits) 1167 *hp++ = clr; 1168 } 1169 } 1170 } else if (((num | ri->ri_xscale) & 1) == 0) { 1171 /* 1172 * Halfword aligned blt. This is needed so the 1173 * 15/16 bit ops can use this function. 1174 */ 1175 num >>= 1; 1176 1177 while (height--) { 1178 dp = rp; 1179 DELTA(rp, ri->ri_stride, int32_t *); 1180 if (ri->ri_hwbits) { 1181 hp = hrp; 1182 DELTA(hrp, ri->ri_stride, int32_t *); 1183 } 1184 1185 for (cnt = num; cnt; cnt--) { 1186 *(int16_t *)dp = clr; 1187 DELTA(dp, 2, int32_t *); 1188 if (ri->ri_hwbits) { 1189 *(int16_t *)hp = clr; 1190 DELTA(hp, 2, int32_t *); 1191 } 1192 } 1193 } 1194 } else { 1195 while (height--) { 1196 dp = rp; 1197 DELTA(rp, ri->ri_stride, int32_t *); 1198 if (ri->ri_hwbits) { 1199 hp = hrp; 1200 DELTA(hrp, ri->ri_stride, int32_t *); 1201 } 1202 1203 for (cnt = num; cnt; cnt--) { 1204 *(u_char *)dp = clr; 1205 DELTA(dp, 1, int32_t *); 1206 if (ri->ri_hwbits) { 1207 *(u_char *)hp = clr; 1208 DELTA(hp, 1, int32_t *); 1209 } 1210 } 1211 } 1212 } 1213 1214 return; 1215 } 1216 1217 slop1 = (4 - ((long)rp & 3)) & 3; 1218 slop2 = (num - slop1) & 3; 1219 num -= slop1 + slop2; 1220 n8 = num >> 5; 1221 num = (num >> 2) & 7; 1222 1223 while (height--) { 1224 dp = rp; 1225 DELTA(rp, ri->ri_stride, int32_t *); 1226 if (ri->ri_hwbits) { 1227 hp = hrp; 1228 DELTA(hrp, ri->ri_stride, int32_t *); 1229 } 1230 1231 /* Align span to 4 bytes */ 1232 if (slop1 & 1) { 1233 *(u_char *)dp = clr; 1234 DELTA(dp, 1, int32_t *); 1235 if (ri->ri_hwbits) { 1236 *(u_char *)hp = clr; 1237 DELTA(hp, 1, int32_t *); 1238 } 1239 } 1240 1241 if (slop1 & 2) { 1242 *(int16_t *)dp = clr; 1243 DELTA(dp, 2, int32_t *); 1244 if (ri->ri_hwbits) { 1245 *(int16_t *)hp = clr; 1246 DELTA(hp, 2, int32_t *); 1247 } 1248 } 1249 1250 /* Write 32 bytes per loop */ 1251 for (cnt = n8; cnt; cnt--) { 1252 for (i = 0; i < 8; i++) { 1253 dp[i] = clr; 1254 if (ri->ri_hwbits) 1255 hp[i] = clr; 1256 } 1257 dp += 8; 1258 if (ri->ri_hwbits) 1259 hp += 8; 1260 } 1261 1262 /* Write 4 bytes per loop */ 1263 for (cnt = num; cnt; cnt--) { 1264 *dp++ = clr; 1265 if (ri->ri_hwbits) 1266 *hp++ = clr; 1267 } 1268 1269 /* Write unaligned trailing slop */ 1270 if (slop2 & 1) { 1271 *(u_char *)dp = clr; 1272 DELTA(dp, 1, int32_t *); 1273 if (ri->ri_hwbits) { 1274 *(u_char *)hp = clr; 1275 DELTA(hp, 1, int32_t *); 1276 } 1277 } 1278 1279 if (slop2 & 2) { 1280 *(int16_t *)dp = clr; 1281 if (ri->ri_hwbits) 1282 *(int16_t *)hp = clr; 1283 } 1284 } 1285 } 1286 1287 #if NRASOPS_ROTATION > 0 1288 /* 1289 * Quarter clockwise rotation routines (originally intended for the 1290 * built-in Zaurus C3x00 display in 16bpp). 1291 */ 1292 1293 #include <sys/malloc.h> 1294 1295 static void 1296 rasops_rotate_font(int *cookie, int rotate) 1297 { 1298 struct rotatedfont *f; 1299 int ncookie; 1300 1301 SLIST_FOREACH(f, &rotatedfonts, rf_next) { 1302 if (f->rf_cookie == *cookie) { 1303 *cookie = f->rf_rotated; 1304 return; 1305 } 1306 } 1307 1308 /* 1309 * We did not find a rotated version of this font. Ask the wsfont 1310 * code to compute one for us. 1311 */ 1312 1313 f = malloc(sizeof(struct rotatedfont), M_DEVBUF, M_WAITOK); 1314 if (f == NULL) 1315 goto fail0; 1316 1317 if ((ncookie = wsfont_rotate(*cookie, rotate)) == -1) 1318 goto fail1; 1319 1320 f->rf_cookie = *cookie; 1321 f->rf_rotated = ncookie; 1322 SLIST_INSERT_HEAD(&rotatedfonts, f, rf_next); 1323 1324 *cookie = ncookie; 1325 return; 1326 1327 fail1: free(f, M_DEVBUF); 1328 fail0: /* Just use the existing font, I guess... */ 1329 return; 1330 } 1331 1332 static void 1333 rasops_copychar(void *cookie, int srcrow, int dstrow, int srccol, int dstcol) 1334 { 1335 struct rasops_info *ri; 1336 u_char *sp, *dp; 1337 int height; 1338 int r_srcrow, r_dstrow, r_srccol, r_dstcol; 1339 1340 ri = (struct rasops_info *)cookie; 1341 1342 r_srcrow = srccol; 1343 r_dstrow = dstcol; 1344 r_srccol = ri->ri_rows - srcrow - 1; 1345 r_dstcol = ri->ri_rows - dstrow - 1; 1346 1347 r_srcrow *= ri->ri_yscale; 1348 r_dstrow *= ri->ri_yscale; 1349 height = ri->ri_font->fontheight; 1350 1351 sp = ri->ri_bits + r_srcrow + r_srccol * ri->ri_xscale; 1352 dp = ri->ri_bits + r_dstrow + r_dstcol * ri->ri_xscale; 1353 1354 while (height--) { 1355 memmove(dp, sp, ri->ri_xscale); 1356 dp += ri->ri_stride; 1357 sp += ri->ri_stride; 1358 } 1359 } 1360 1361 static void 1362 rasops_putchar_rotated_cw(void *cookie, int row, int col, u_int uc, long attr) 1363 { 1364 struct rasops_info *ri; 1365 u_char *rp; 1366 int height; 1367 1368 ri = (struct rasops_info *)cookie; 1369 1370 if (__predict_false((unsigned int)row > ri->ri_rows || 1371 (unsigned int)col > ri->ri_cols)) 1372 return; 1373 1374 /* Avoid underflow */ 1375 if ((ri->ri_rows - row - 1) < 0) 1376 return; 1377 1378 /* Do rotated char sans (side)underline */ 1379 ri->ri_real_ops.putchar(cookie, col, ri->ri_rows - row - 1, uc, 1380 attr & ~1); 1381 1382 /* Do rotated underline */ 1383 rp = ri->ri_bits + col * ri->ri_yscale + (ri->ri_rows - row - 1) * 1384 ri->ri_xscale; 1385 height = ri->ri_font->fontheight; 1386 1387 /* XXX this assumes 16-bit color depth */ 1388 if ((attr & 1) != 0) { 1389 int16_t c = (int16_t)ri->ri_devcmap[((u_int)attr >> 24) & 0xf]; 1390 1391 while (height--) { 1392 *(int16_t *)rp = c; 1393 rp += ri->ri_stride; 1394 } 1395 } 1396 } 1397 1398 static void 1399 rasops_erasecols_rotated_cw(void *cookie, int row, int col, int num, long attr) 1400 { 1401 struct rasops_info *ri; 1402 int i; 1403 1404 ri = (struct rasops_info *)cookie; 1405 1406 for (i = col; i < col + num; i++) 1407 ri->ri_ops.putchar(cookie, row, i, ' ', attr); 1408 } 1409 1410 /* XXX: these could likely be optimised somewhat. */ 1411 static void 1412 rasops_copyrows_rotated_cw(void *cookie, int src, int dst, int num) 1413 { 1414 struct rasops_info *ri = (struct rasops_info *)cookie; 1415 int col, roff; 1416 1417 if (src > dst) 1418 for (roff = 0; roff < num; roff++) 1419 for (col = 0; col < ri->ri_cols; col++) 1420 rasops_copychar(cookie, src + roff, dst + roff, 1421 col, col); 1422 else 1423 for (roff = num - 1; roff >= 0; roff--) 1424 for (col = 0; col < ri->ri_cols; col++) 1425 rasops_copychar(cookie, src + roff, dst + roff, 1426 col, col); 1427 } 1428 1429 static void 1430 rasops_copycols_rotated_cw(void *cookie, int row, int src, int dst, int num) 1431 { 1432 int coff; 1433 1434 if (src > dst) 1435 for (coff = 0; coff < num; coff++) 1436 rasops_copychar(cookie, row, row, src + coff, dst + coff); 1437 else 1438 for (coff = num - 1; coff >= 0; coff--) 1439 rasops_copychar(cookie, row, row, src + coff, dst + coff); 1440 } 1441 1442 static void 1443 rasops_eraserows_rotated_cw(void *cookie, int row, int num, long attr) 1444 { 1445 struct rasops_info *ri; 1446 int col, rn; 1447 1448 ri = (struct rasops_info *)cookie; 1449 1450 for (rn = row; rn < row + num; rn++) 1451 for (col = 0; col < ri->ri_cols; col++) 1452 ri->ri_ops.putchar(cookie, rn, col, ' ', attr); 1453 } 1454 1455 /* 1456 * Quarter counter-clockwise rotation routines (originally intended for the 1457 * built-in Sharp W-ZERO3 display in 16bpp). 1458 */ 1459 static void 1460 rasops_copychar_ccw(void *cookie, int srcrow, int dstrow, int srccol, int dstcol) 1461 { 1462 struct rasops_info *ri; 1463 u_char *sp, *dp; 1464 int height; 1465 int r_srcrow, r_dstrow, r_srccol, r_dstcol; 1466 1467 ri = (struct rasops_info *)cookie; 1468 1469 r_srcrow = ri->ri_cols - srccol - 1; 1470 r_dstrow = ri->ri_cols - dstcol - 1; 1471 r_srccol = srcrow; 1472 r_dstcol = dstrow; 1473 1474 r_srcrow *= ri->ri_yscale; 1475 r_dstrow *= ri->ri_yscale; 1476 height = ri->ri_font->fontheight; 1477 1478 sp = ri->ri_bits + r_srcrow + r_srccol * ri->ri_xscale; 1479 dp = ri->ri_bits + r_dstrow + r_dstcol * ri->ri_xscale; 1480 1481 while (height--) { 1482 memmove(dp, sp, ri->ri_xscale); 1483 dp += ri->ri_stride; 1484 sp += ri->ri_stride; 1485 } 1486 } 1487 1488 static void 1489 rasops_putchar_rotated_ccw(void *cookie, int row, int col, u_int uc, long attr) 1490 { 1491 struct rasops_info *ri; 1492 u_char *rp; 1493 int height; 1494 1495 ri = (struct rasops_info *)cookie; 1496 1497 if (__predict_false((unsigned int)row > ri->ri_rows || 1498 (unsigned int)col > ri->ri_cols)) 1499 return; 1500 1501 /* Avoid underflow */ 1502 if ((ri->ri_cols - col - 1) < 0) 1503 return; 1504 1505 /* Do rotated char sans (side)underline */ 1506 ri->ri_real_ops.putchar(cookie, ri->ri_cols - col - 1, row, uc, 1507 attr & ~1); 1508 1509 /* Do rotated underline */ 1510 rp = ri->ri_bits + (ri->ri_cols - col - 1) * ri->ri_yscale + 1511 row * ri->ri_xscale + 1512 (ri->ri_font->fontwidth - 1) * ri->ri_pelbytes; 1513 height = ri->ri_font->fontheight; 1514 1515 /* XXX this assumes 16-bit color depth */ 1516 if ((attr & 1) != 0) { 1517 int16_t c = (int16_t)ri->ri_devcmap[((u_int)attr >> 24) & 0xf]; 1518 1519 while (height--) { 1520 *(int16_t *)rp = c; 1521 rp += ri->ri_stride; 1522 } 1523 } 1524 } 1525 1526 /* XXX: these could likely be optimised somewhat. */ 1527 static void 1528 rasops_copyrows_rotated_ccw(void *cookie, int src, int dst, int num) 1529 { 1530 struct rasops_info *ri = (struct rasops_info *)cookie; 1531 int col, roff; 1532 1533 if (src > dst) 1534 for (roff = 0; roff < num; roff++) 1535 for (col = 0; col < ri->ri_cols; col++) 1536 rasops_copychar_ccw(cookie, 1537 src + roff, dst + roff, col, col); 1538 else 1539 for (roff = num - 1; roff >= 0; roff--) 1540 for (col = 0; col < ri->ri_cols; col++) 1541 rasops_copychar_ccw(cookie, 1542 src + roff, dst + roff, col, col); 1543 } 1544 1545 static void 1546 rasops_copycols_rotated_ccw(void *cookie, int row, int src, int dst, int num) 1547 { 1548 int coff; 1549 1550 if (src > dst) 1551 for (coff = 0; coff < num; coff++) 1552 rasops_copychar_ccw(cookie, row, row, 1553 src + coff, dst + coff); 1554 else 1555 for (coff = num - 1; coff >= 0; coff--) 1556 rasops_copychar_ccw(cookie, row, row, 1557 src + coff, dst + coff); 1558 } 1559 #endif /* NRASOPS_ROTATION */ 1560 1561 void 1562 rasops_make_box_chars_16(struct rasops_info *ri) 1563 { 1564 uint16_t vert_mask, hmask_left, hmask_right; 1565 uint16_t *data = (uint16_t *)ri->ri_optfont.data; 1566 int c, i, mid; 1567 1568 vert_mask = 0xc000 >> ((ri->ri_font->fontwidth >> 1) - 1); 1569 hmask_left = 0xff00 << (8 - (ri->ri_font->fontwidth >> 1)); 1570 hmask_right = hmask_left >> ((ri->ri_font->fontwidth + 1)>> 1); 1571 mid = (ri->ri_font->fontheight + 1) >> 1; 1572 1573 /* 0x00 would be empty anyway so don't bother */ 1574 for (c = 1; c < 16; c++) { 1575 data += ri->ri_font->fontheight; 1576 if (c & 1) { 1577 /* upper segment */ 1578 for (i = 0; i < mid; i++) 1579 data[i] = vert_mask; 1580 } 1581 if (c & 4) { 1582 /* lower segment */ 1583 for (i = mid; i < ri->ri_font->fontheight; i++) 1584 data[i] = vert_mask; 1585 } 1586 if (c & 2) { 1587 /* right segment */ 1588 i = ri->ri_font->fontheight >> 1; 1589 data[mid - 1] |= hmask_right; 1590 data[mid] |= hmask_right; 1591 } 1592 if (c & 8) { 1593 /* left segment */ 1594 data[mid - 1] |= hmask_left; 1595 data[mid] |= hmask_left; 1596 } 1597 } 1598 } 1599 1600 void 1601 rasops_make_box_chars_8(struct rasops_info *ri) 1602 { 1603 uint8_t vert_mask, hmask_left, hmask_right; 1604 uint8_t *data = (uint8_t *)ri->ri_optfont.data; 1605 int c, i, mid; 1606 1607 vert_mask = 0xc0 >> ((ri->ri_font->fontwidth >> 1) - 1); 1608 hmask_left = 0xf0 << (4 - (ri->ri_font->fontwidth >> 1)); 1609 hmask_right = hmask_left >> ((ri->ri_font->fontwidth + 1)>> 1); 1610 mid = (ri->ri_font->fontheight + 1) >> 1; 1611 1612 /* 0x00 would be empty anyway so don't bother */ 1613 for (c = 1; c < 16; c++) { 1614 data += ri->ri_font->fontheight; 1615 if (c & 1) { 1616 /* upper segment */ 1617 for (i = 0; i < mid; i++) 1618 data[i] = vert_mask; 1619 } 1620 if (c & 4) { 1621 /* lower segment */ 1622 for (i = mid; i < ri->ri_font->fontheight; i++) 1623 data[i] = vert_mask; 1624 } 1625 if (c & 2) { 1626 /* right segment */ 1627 i = ri->ri_font->fontheight >> 1; 1628 data[mid - 1] |= hmask_right; 1629 data[mid] |= hmask_right; 1630 } 1631 if (c & 8) { 1632 /* left segment */ 1633 data[mid - 1] |= hmask_left; 1634 data[mid] |= hmask_left; 1635 } 1636 } 1637 } 1638 1639 void 1640 rasops_make_box_chars_32(struct rasops_info *ri) 1641 { 1642 uint32_t vert_mask, hmask_left, hmask_right; 1643 uint32_t *data = (uint32_t *)ri->ri_optfont.data; 1644 int c, i, mid; 1645 1646 vert_mask = 0xc0000000 >> ((ri->ri_font->fontwidth >> 1) - 1); 1647 hmask_left = 0xffff0000 << (16 - (ri->ri_font->fontwidth >> 1)); 1648 hmask_right = hmask_left >> ((ri->ri_font->fontwidth + 1)>> 1); 1649 mid = (ri->ri_font->fontheight + 1) >> 1; 1650 1651 /* 0x00 would be empty anyway so don't bother */ 1652 for (c = 1; c < 16; c++) { 1653 data += ri->ri_font->fontheight; 1654 if (c & 1) { 1655 /* upper segment */ 1656 for (i = 0; i < mid; i++) 1657 data[i] = vert_mask; 1658 } 1659 if (c & 4) { 1660 /* lower segment */ 1661 for (i = mid; i < ri->ri_font->fontheight; i++) 1662 data[i] = vert_mask; 1663 } 1664 if (c & 2) { 1665 /* right segment */ 1666 i = ri->ri_font->fontheight >> 1; 1667 data[mid - 1] |= hmask_right; 1668 data[mid] |= hmask_right; 1669 } 1670 if (c & 8) { 1671 /* left segment */ 1672 data[mid - 1] |= hmask_left; 1673 data[mid] |= hmask_left; 1674 } 1675 } 1676 } 1677 1678 void 1679 rasops_make_box_chars_alpha(struct rasops_info *ri) 1680 { 1681 uint8_t *data = (uint8_t *)ri->ri_optfont.data; 1682 uint8_t *ddata; 1683 int c, i, hmid, vmid, wi, he; 1684 1685 wi = ri->ri_font->fontwidth; 1686 he = ri->ri_font->fontheight; 1687 1688 vmid = (he + 1) >> 1; 1689 hmid = (wi + 1) >> 1; 1690 1691 /* 0x00 would be empty anyway so don't bother */ 1692 for (c = 1; c < 16; c++) { 1693 data += ri->ri_fontscale; 1694 if (c & 1) { 1695 /* upper segment */ 1696 ddata = data + hmid; 1697 for (i = 0; i <= vmid; i++) { 1698 *ddata = 0xff; 1699 ddata += wi; 1700 } 1701 } 1702 if (c & 4) { 1703 /* lower segment */ 1704 ddata = data + wi * vmid + hmid; 1705 for (i = vmid; i < he; i++) { 1706 *ddata = 0xff; 1707 ddata += wi; 1708 } 1709 } 1710 if (c & 2) { 1711 /* right segment */ 1712 ddata = data + wi * vmid + hmid; 1713 for (i = hmid; i < wi; i++) { 1714 *ddata = 0xff; 1715 ddata++; 1716 } 1717 } 1718 if (c & 8) { 1719 /* left segment */ 1720 ddata = data + wi * vmid; 1721 for (i = 0; i <= hmid; i++) { 1722 *ddata = 0xff; 1723 ddata++; 1724 } 1725 } 1726 } 1727 } 1728 1729 /* 1730 * Return a colour map appropriate for the given struct rasops_info in the 1731 * same form used by rasops_cmap[] 1732 * For now this is either a copy of rasops_cmap[] or an R3G3B2 map, it should 1733 * probably be a linear ( or gamma corrected? ) ramp for higher depths. 1734 */ 1735 1736 int 1737 rasops_get_cmap(struct rasops_info *ri, uint8_t *palette, size_t bytes) 1738 { 1739 if ((ri->ri_depth == 8 ) && ((ri->ri_flg & RI_8BIT_IS_RGB) > 0)) { 1740 /* generate an R3G3B2 palette */ 1741 int i, idx = 0; 1742 uint8_t tmp; 1743 1744 if (bytes < 768) 1745 return EINVAL; 1746 for (i = 0; i < 256; i++) { 1747 tmp = i & 0xe0; 1748 /* 1749 * replicate bits so 0xe0 maps to a red value of 0xff 1750 * in order to make white look actually white 1751 */ 1752 tmp |= (tmp >> 3) | (tmp >> 6); 1753 palette[idx] = tmp; 1754 idx++; 1755 1756 tmp = (i & 0x1c) << 3; 1757 tmp |= (tmp >> 3) | (tmp >> 6); 1758 palette[idx] = tmp; 1759 idx++; 1760 1761 tmp = (i & 0x03) << 6; 1762 tmp |= tmp >> 2; 1763 tmp |= tmp >> 4; 1764 palette[idx] = tmp; 1765 idx++; 1766 } 1767 } else { 1768 memcpy(palette, rasops_cmap, MIN(bytes, sizeof(rasops_cmap))); 1769 } 1770 return 0; 1771 } 1772