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