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