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