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