rasops.c revision 1.91
1/* $NetBSD: rasops.c,v 1.91 2019/07/26 10:48:45 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.91 2019/07/26 10:48:45 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 > 0 || 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_REVERSE) != 0) { 622 uint32_t swap = fg; 623 fg = bg; 624 bg = swap; 625 } 626 627 if ((flg & WSATTR_HILIT) != 0) 628 fg += 8; 629 630 flg = 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 & WSATTR_UNDERLINE) ? 7 : 6); 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; 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 705 sp = ri->ri_bits + src * ri->ri_yscale; 706 dp = ri->ri_bits + dst * ri->ri_yscale; 707 if (ri->ri_hwbits) 708 hp = ri->ri_hwbits + dst * ri->ri_yscale; 709 710 while (num--) { 711 memmove(dp, sp, n); 712 dp += n; 713 if (ri->ri_hwbits) { 714 memcpy(hp, sp, n); 715 hp += n; 716 } 717 sp += n; 718 } 719} 720 721/* 722 * Copy columns. This is slow, and hard to optimize due to alignment, 723 * and the fact that we have to copy both left->right and right->left. 724 * We simply cop-out here and use memmove(), since it handles all of 725 * these cases anyway. 726 */ 727void 728rasops_copycols(void *cookie, int row, int src, int dst, int num) 729{ 730 struct rasops_info *ri = (struct rasops_info *)cookie; 731 uint8_t *sp, *dp, *hp; 732 int height; 733 734 hp = NULL; /* XXX GCC */ 735 736#ifdef RASOPS_CLIPPING 737 if (dst == src) 738 return; 739 740 /* Catches < 0 case too */ 741 if ((unsigned)row >= (unsigned)ri->ri_rows) 742 return; 743 744 if (src < 0) { 745 num += src; 746 src = 0; 747 } 748 749 if (src + num > ri->ri_cols) 750 num = ri->ri_cols - src; 751 752 if (dst < 0) { 753 num += dst; 754 dst = 0; 755 } 756 757 if (dst + num > ri->ri_cols) 758 num = ri->ri_cols - dst; 759 760 if (num <= 0) 761 return; 762#endif 763 764 num *= ri->ri_xscale; 765 row *= ri->ri_yscale; 766 height = ri->ri_font->fontheight; 767 768 sp = ri->ri_bits + row + src * ri->ri_xscale; 769 dp = ri->ri_bits + row + dst * ri->ri_xscale; 770 if (ri->ri_hwbits) 771 hp = ri->ri_hwbits + row + dst * ri->ri_xscale; 772 773 while (height--) { 774 memmove(dp, sp, num); 775 dp += ri->ri_stride; 776 if (ri->ri_hwbits) { 777 memcpy(hp, sp, num); 778 hp += ri->ri_stride; 779 } 780 sp += ri->ri_stride; 781 } 782} 783 784/* 785 * Turn cursor off/on. 786 */ 787static void 788rasops_cursor(void *cookie, int on, int row, int col) 789{ 790 struct rasops_info *ri = (struct rasops_info *)cookie; 791 792 /* Turn old cursor off */ 793 if ((ri->ri_flg & RI_CURSOR) != 0) 794#ifdef RASOPS_CLIPPING 795 if ((ri->ri_flg & RI_CURSORCLIP) == 0) 796#endif 797 ri->ri_do_cursor(ri); 798 799 /* Select new cursor */ 800#ifdef RASOPS_CLIPPING 801 ri->ri_flg &= ~RI_CURSORCLIP; 802 803 if (row < 0 || row >= ri->ri_rows) 804 ri->ri_flg |= RI_CURSORCLIP; 805 else if (col < 0 || col >= ri->ri_cols) 806 ri->ri_flg |= RI_CURSORCLIP; 807#endif 808 ri->ri_crow = row; 809 ri->ri_ccol = col; 810 811 if (on) { 812 ri->ri_flg |= RI_CURSOR; 813#ifdef RASOPS_CLIPPING 814 if ((ri->ri_flg & RI_CURSORCLIP) == 0) 815#endif 816 ri->ri_do_cursor(ri); 817 } else 818 ri->ri_flg &= ~RI_CURSOR; 819} 820 821/* 822 * Make the device colormap 823 */ 824static void 825rasops_init_devcmap(struct rasops_info *ri) 826{ 827 int i; 828 uint32_t c; 829 const uint8_t *p; 830 831 switch (ri->ri_depth) { 832 case 1: 833 ri->ri_devcmap[0] = 0; 834 for (i = 1; i < 16; i++) 835 ri->ri_devcmap[i] = -1; 836 return; 837 838 case 2: 839 for (i = 1; i < 15; i++) 840 ri->ri_devcmap[i] = 0xaaaaaaaa; 841 842 ri->ri_devcmap[0] = 0; 843 ri->ri_devcmap[8] = 0x55555555; 844 ri->ri_devcmap[15] = -1; 845 return; 846 847#ifdef RASOPS_APPLE_PALETTE 848 case 4: 849 for (i = 0; i < 16; i++) { 850 c = apple4_devcmap[i]; 851 ri->ri_devcmap[i] = 852 (c << 0) | (c << 4) | (c << 8) | (c << 12) | 853 (c << 16) | (c << 20) | (c << 24) | (c << 28); 854 } 855 return; 856#else 857 /* XXXRO What should we do here? */ 858#endif 859 860 case 8: 861 if ((ri->ri_flg & RI_8BIT_IS_RGB) == 0) { 862 for (i = 0; i < 16; i++) { 863#ifdef RASOPS_APPLE_PALETTE 864 c = apple8_devcmap[i]; 865#else 866 c = i; 867#endif 868 ri->ri_devcmap[i] = 869 c | (c << 8) | (c << 16) | (c << 24); 870 } 871 return; 872 } 873 } 874 875 p = rasops_cmap; 876 877 for (i = 0; i < 16; i++) { 878 if (ri->ri_rnum <= 8) 879 c = (uint32_t)(*p >> (8 - ri->ri_rnum)) << ri->ri_rpos; 880 else 881 c = (uint32_t)(*p << (ri->ri_rnum - 8)) << ri->ri_rpos; 882 p++; 883 884 if (ri->ri_gnum <= 8) 885 c |= (uint32_t)(*p >> (8 - ri->ri_gnum)) << ri->ri_gpos; 886 else 887 c |= (uint32_t)(*p << (ri->ri_gnum - 8)) << ri->ri_gpos; 888 p++; 889 890 if (ri->ri_bnum <= 8) 891 c |= (uint32_t)(*p >> (8 - ri->ri_bnum)) << ri->ri_bpos; 892 else 893 c |= (uint32_t)(*p << (ri->ri_bnum - 8)) << ri->ri_bpos; 894 p++; 895 896 /* Fill the word for generic routines, which want this */ 897 if (ri->ri_depth == 8) { 898 c |= c << 8; 899 c |= c << 16; 900 } else if (ri->ri_depth == 15 || ri->ri_depth == 16) 901 c |= c << 16; 902 else if (ri->ri_depth == 24) 903 c |= (c & 0xff) << 24; 904 905 /* 24bpp does bswap on the fly. {32,16,15}bpp do it here. */ 906 if ((ri->ri_flg & RI_BSWAP) == 0) 907 ri->ri_devcmap[i] = c; 908 else if (ri->ri_depth == 15 || ri->ri_depth == 16) 909 ri->ri_devcmap[i] = bswap16(c); 910 else if (ri->ri_depth == 32) 911 ri->ri_devcmap[i] = bswap32(c); 912 else /* 8, 24 */ 913 ri->ri_devcmap[i] = c; 914 } 915} 916 917/* 918 * Unpack a rasops attribute 919 */ 920void 921rasops_unpack_attr(long attr, int *fg, int *bg, int *underline) 922{ 923 924 *fg = ((uint32_t)attr >> 24) & 0xf; 925 *bg = ((uint32_t)attr >> 16) & 0xf; 926 if (underline != NULL) 927 *underline = (uint32_t)attr & WSATTR_UNDERLINE; 928} 929 930/* 931 * Erase rows. This isn't static, since 24-bpp uses it in special cases. 932 */ 933void 934rasops_eraserows(void *cookie, int row, int num, long attr) 935{ 936 struct rasops_info *ri = (struct rasops_info *)cookie; 937 uint32_t *dp, *hp, clr; 938 int n, cnt, delta; 939 940 hp = NULL; /* XXX GCC */ 941 942#ifdef RASOPS_CLIPPING 943 if (row < 0) { 944 num += row; 945 row = 0; 946 } 947 948 if (row + num > ri->ri_rows) 949 num = ri->ri_rows - row; 950 951 if (num <= 0) 952 return; 953#endif 954 955 clr = ri->ri_devcmap[(attr >> 16) & 0xf]; 956 957 /* 958 * XXX The wsdisplay_emulops interface seems a little deficient in 959 * that there is no way to clear the *entire* screen. We provide a 960 * workaround here: if the entire console area is being cleared, and 961 * the RI_FULLCLEAR flag is set, clear the entire display. 962 */ 963 if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR) != 0) { 964 n = ri->ri_stride >> 2; 965 num = ri->ri_height; 966 dp = (uint32_t *)ri->ri_origbits; 967 if (ri->ri_hwbits) 968 hp = (uint32_t *)ri->ri_hworigbits; 969 delta = 0; 970 } else { 971 n = ri->ri_emustride >> 2; 972 num *= ri->ri_font->fontheight; 973 dp = (uint32_t *)(ri->ri_bits + row * ri->ri_yscale); 974 if (ri->ri_hwbits) 975 hp = (uint32_t *)(ri->ri_hwbits + row * 976 ri->ri_yscale); 977 delta = ri->ri_delta; 978 } 979 980 while (num--) { 981 for (cnt = n; cnt; cnt--) { 982 *dp++ = clr; 983 if (ri->ri_hwbits) 984 *hp++ = clr; 985 } 986 DELTA(dp, delta, uint32_t *); 987 if (ri->ri_hwbits) 988 DELTA(hp, delta, uint32_t *); 989 } 990} 991 992/* 993 * Actually turn the cursor on or off. This does the dirty work for 994 * rasops_cursor(). 995 */ 996static void 997rasops_do_cursor(struct rasops_info *ri) 998{ 999 int full, height, cnt, slop1, slop2, row, col; 1000 uint32_t tmp32, msk1, msk2; 1001 uint8_t tmp8; 1002 uint8_t *dp, *rp, *hrp, *hp; 1003 1004 hrp = hp = NULL; /* XXX GCC */ 1005 1006#if NRASOPS_ROTATION > 0 1007 if (ri->ri_flg & RI_ROTATE_MASK) { 1008 if (ri->ri_flg & RI_ROTATE_CW) { 1009 /* Rotate rows/columns */ 1010 row = ri->ri_ccol; 1011 col = ri->ri_rows - ri->ri_crow - 1; 1012 } else if (ri->ri_flg & RI_ROTATE_CCW) { 1013 /* Rotate rows/columns */ 1014 row = ri->ri_cols - ri->ri_ccol - 1; 1015 col = ri->ri_crow; 1016 } else { /* upside-down */ 1017 row = ri->ri_crow; 1018 col = ri->ri_ccol; 1019 } 1020 } else 1021#endif 1022 { 1023 row = ri->ri_crow; 1024 col = ri->ri_ccol; 1025 } 1026 1027 rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale; 1028 if (ri->ri_hwbits) 1029 hrp = ri->ri_hwbits + row * ri->ri_yscale + col 1030 * ri->ri_xscale; 1031 height = ri->ri_font->fontheight; 1032 1033 /* 1034 * For ri_xscale = 1: 1035 * 1036 * Logic below does not work for ri_xscale = 1, e.g., 1037 * fontwidth = 8 and bpp = 1. So we take care of it. 1038 */ 1039 if (ri->ri_xscale == 1) { 1040 while (height--) { 1041 tmp8 = ~*rp; 1042 1043 *rp = tmp8; 1044 rp += ri->ri_stride; 1045 1046 if (ri->ri_hwbits) { 1047 *hrp = tmp8; 1048 hrp += ri->ri_stride; 1049 } 1050 } 1051 return; 1052 } 1053 1054 /* 1055 * For ri_xscale = 2, 3, 4, ...: 1056 * 1057 * Note that siop1 <= ri_xscale even for ri_xscale = 2, 1058 * since rp % 3 = 0 or 2 (ri_stride % 4 = 0). 1059 */ 1060 slop1 = (4 - ((uintptr_t)rp & 3)) & 3; 1061 slop2 = (ri->ri_xscale - slop1) & 3; 1062 full = (ri->ri_xscale - slop1 /* - slop2 */) >> 2; 1063 1064 rp = (uint8_t *)((uintptr_t)rp & ~3); 1065 hrp = (uint8_t *)((uintptr_t)hrp & ~3); 1066 1067 msk1 = !slop1 ? 0 : be32toh(0xffffffffU >> (32 - (8 * slop1))); 1068 msk2 = !slop2 ? 0 : be32toh(0xffffffffU << (32 - (8 * slop2))); 1069 1070 while (height--) { 1071 dp = rp; 1072 rp += ri->ri_stride; 1073 if (ri->ri_hwbits) { 1074 hp = hrp; 1075 hrp += ri->ri_stride; 1076 } 1077 1078 if (slop1) { 1079 tmp32 = *(uint32_t *)dp ^ msk1; 1080 *(uint32_t *)dp = tmp32; 1081 dp += 4; 1082 if (ri->ri_hwbits) { 1083 *(uint32_t *)hp = tmp32; 1084 hp += 4; 1085 } 1086 } 1087 1088 for (cnt = full; cnt; cnt--) { 1089 tmp32 = ~*(uint32_t *)dp; 1090 *(uint32_t *)dp = tmp32; 1091 dp += 4; 1092 if (ri->ri_hwbits) { 1093 *(uint32_t *)hp = tmp32; 1094 hp += 4; 1095 } 1096 } 1097 1098 if (slop2) { 1099 tmp32 = *(uint32_t *)dp ^ msk2; 1100 *(uint32_t *)dp = tmp32; 1101 if (ri->ri_hwbits) 1102 *(uint32_t *)hp = tmp32; 1103 } 1104 } 1105} 1106 1107/* 1108 * Erase columns. 1109 */ 1110void 1111rasops_erasecols(void *cookie, int row, int col, int num, long attr) 1112{ 1113 struct rasops_info *ri = (struct rasops_info *)cookie; 1114 int height, cnt, slop1, slop2, clr; 1115 uint32_t *rp, *dp, *hrp, *hp; 1116 1117 hrp = hp = NULL; /* XXX GCC */ 1118 1119#ifdef RASOPS_CLIPPING 1120 if ((unsigned)row >= (unsigned)ri->ri_rows) 1121 return; 1122 1123 if (col < 0) { 1124 num += col; 1125 col = 0; 1126 } 1127 1128 if ((col + num) > ri->ri_cols) 1129 num = ri->ri_cols - col; 1130 1131 if (num <= 0) 1132 return; 1133#endif 1134 1135 num *= ri->ri_xscale; 1136 rp = (uint32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale); 1137 if (ri->ri_hwbits) 1138 hrp = (uint32_t *)(ri->ri_hwbits + row*ri->ri_yscale + 1139 col*ri->ri_xscale); 1140 height = ri->ri_font->fontheight; 1141 clr = ri->ri_devcmap[(attr >> 16) & 0xf]; 1142 1143 /* Don't bother using the full loop for <= 32 pels */ 1144 if (num <= 32) { 1145 if (((num | ri->ri_xscale) & 3) == 0) { 1146 /* Word aligned blt */ 1147 num >>= 2; 1148 1149 while (height--) { 1150 dp = rp; 1151 DELTA(rp, ri->ri_stride, uint32_t *); 1152 if (ri->ri_hwbits) { 1153 hp = hrp; 1154 DELTA(hrp, ri->ri_stride, uint32_t *); 1155 } 1156 1157 for (cnt = num; cnt; cnt--) { 1158 *dp++ = clr; 1159 if (ri->ri_hwbits) 1160 *hp++ = clr; 1161 } 1162 } 1163 } else if (((num | ri->ri_xscale) & 1) == 0) { 1164 /* 1165 * Halfword aligned blt. This is needed so the 1166 * 15/16 bit ops can use this function. 1167 */ 1168 num >>= 1; 1169 1170 while (height--) { 1171 dp = rp; 1172 DELTA(rp, ri->ri_stride, uint32_t *); 1173 if (ri->ri_hwbits) { 1174 hp = hrp; 1175 DELTA(hrp, ri->ri_stride, uint32_t *); 1176 } 1177 1178 for (cnt = num; cnt; cnt--) { 1179 *(uint16_t *)dp = clr; 1180 DELTA(dp, 2, uint32_t *); 1181 if (ri->ri_hwbits) { 1182 *(uint16_t *)hp = clr; 1183 DELTA(hp, 2, uint32_t *); 1184 } 1185 } 1186 } 1187 } else { 1188 while (height--) { 1189 memset(rp, clr, num); 1190 DELTA(rp, ri->ri_stride, uint32_t *); 1191 if (ri->ri_hwbits) { 1192 memset(hrp, clr, num); 1193 DELTA(hrp, ri->ri_stride, uint32_t *); 1194 } 1195 } 1196 } 1197 1198 return; 1199 } 1200 1201 slop1 = (4 - ((uintptr_t)rp & 3)) & 3; 1202 slop2 = (num - slop1) & 3; 1203 num = (num - slop1 /* - slop2 */) >> 2; 1204 1205 while (height--) { 1206 dp = rp; 1207 DELTA(rp, ri->ri_stride, uint32_t *); 1208 if (ri->ri_hwbits) { 1209 hp = hrp; 1210 DELTA(hrp, ri->ri_stride, uint32_t *); 1211 } 1212 1213 /* Align span to 4 bytes */ 1214 if (slop1 & 1) { 1215 *(uint8_t *)dp = clr; 1216 DELTA(dp, 1, uint32_t *); 1217 if (ri->ri_hwbits) { 1218 *(uint8_t *)hp = clr; 1219 DELTA(hp, 1, uint32_t *); 1220 } 1221 } 1222 1223 if (slop1 & 2) { 1224 *(uint16_t *)dp = clr; 1225 DELTA(dp, 2, uint32_t *); 1226 if (ri->ri_hwbits) { 1227 *(uint16_t *)hp = clr; 1228 DELTA(hp, 2, uint32_t *); 1229 } 1230 } 1231 1232 /* Write 4 bytes per loop */ 1233 for (cnt = num; cnt; cnt--) { 1234 *dp++ = clr; 1235 if (ri->ri_hwbits) 1236 *hp++ = clr; 1237 } 1238 1239 /* Write unaligned trailing slop */ 1240 if (slop2 & 1) { 1241 *(uint8_t *)dp = clr; 1242 DELTA(dp, 1, uint32_t *); 1243 if (ri->ri_hwbits) { 1244 *(uint8_t *)hp = clr; 1245 DELTA(hp, 1, uint32_t *); 1246 } 1247 } 1248 1249 if (slop2 & 2) { 1250 *(uint16_t *)dp = clr; 1251 if (ri->ri_hwbits) 1252 *(uint16_t *)hp = clr; 1253 } 1254 } 1255} 1256 1257#if NRASOPS_ROTATION > 0 1258/* 1259 * Quarter clockwise rotation routines (originally intended for the 1260 * built-in Zaurus C3x00 display in 16bpp). 1261 */ 1262 1263static void 1264rasops_rotate_font(int *cookie, int rotate) 1265{ 1266 struct rotatedfont *f; 1267 int ncookie; 1268 1269 SLIST_FOREACH(f, &rotatedfonts, rf_next) { 1270 if (f->rf_cookie == *cookie) { 1271 *cookie = f->rf_rotated; 1272 return; 1273 } 1274 } 1275 1276 /* 1277 * We did not find a rotated version of this font. Ask the wsfont 1278 * code to compute one for us. 1279 */ 1280 1281 f = kmem_alloc(sizeof(*f), KM_SLEEP); 1282 1283 if ((ncookie = wsfont_rotate(*cookie, rotate)) == -1) 1284 goto fail; 1285 1286 f->rf_cookie = *cookie; 1287 f->rf_rotated = ncookie; 1288 SLIST_INSERT_HEAD(&rotatedfonts, f, rf_next); 1289 1290 *cookie = ncookie; 1291 return; 1292 1293fail: free(f, sizeof(*f)); 1294 return; 1295} 1296 1297static void 1298rasops_copychar(void *cookie, int srcrow, int dstrow, int srccol, int dstcol) 1299{ 1300 struct rasops_info *ri = (struct rasops_info *)cookie; 1301 int height; 1302 int r_srcrow, r_dstrow, r_srccol, r_dstcol; 1303 uint8_t *sp, *dp; 1304 1305 r_srcrow = srccol; 1306 r_dstrow = dstcol; 1307 r_srccol = ri->ri_rows - srcrow - 1; 1308 r_dstcol = ri->ri_rows - dstrow - 1; 1309 1310 r_srcrow *= ri->ri_yscale; 1311 r_dstrow *= ri->ri_yscale; 1312 height = ri->ri_font->fontheight; 1313 1314 sp = ri->ri_bits + r_srcrow + r_srccol * ri->ri_xscale; 1315 dp = ri->ri_bits + r_dstrow + r_dstcol * ri->ri_xscale; 1316 1317 while (height--) { 1318 memmove(dp, sp, ri->ri_xscale); 1319 dp += ri->ri_stride; 1320 sp += ri->ri_stride; 1321 } 1322} 1323 1324static void 1325rasops_putchar_rotated_cw(void *cookie, int row, int col, u_int uc, long attr) 1326{ 1327 struct rasops_info *ri = (struct rasops_info *)cookie; 1328 int height; 1329 uint8_t *rp; 1330 1331 if (__predict_false((unsigned int)row > ri->ri_rows || 1332 (unsigned int)col > ri->ri_cols)) 1333 return; 1334 1335 /* Avoid underflow */ 1336 if (ri->ri_rows - row - 1 < 0) 1337 return; 1338 1339 /* Do rotated char sans (side)underline */ 1340 ri->ri_real_ops.putchar(cookie, col, ri->ri_rows - row - 1, uc, 1341 attr & ~WSATTR_UNDERLINE); 1342 1343 /* Do rotated underline */ 1344 rp = ri->ri_bits + col * ri->ri_yscale + (ri->ri_rows - row - 1) * 1345 ri->ri_xscale; 1346 height = ri->ri_font->fontheight; 1347 1348 /* XXX this assumes 16-bit color depth */ 1349 if ((attr & WSATTR_UNDERLINE) != 0) { 1350 uint16_t c = 1351 (uint16_t)ri->ri_devcmap[((u_int)attr >> 24) & 0xf]; 1352 1353 while (height--) { 1354 *(uint16_t *)rp = c; 1355 rp += ri->ri_stride; 1356 } 1357 } 1358} 1359 1360static void 1361rasops_erasecols_rotated_cw(void *cookie, int row, int col, int num, long attr) 1362{ 1363 struct rasops_info *ri = (struct rasops_info *)cookie; 1364 int i; 1365 1366 for (i = col; i < col + num; i++) 1367 ri->ri_ops.putchar(cookie, row, i, ' ', attr); 1368} 1369 1370/* XXX: these could likely be optimised somewhat. */ 1371static void 1372rasops_copyrows_rotated_cw(void *cookie, int src, int dst, int num) 1373{ 1374 struct rasops_info *ri = (struct rasops_info *)cookie; 1375 int col, roff; 1376 1377 if (src > dst) 1378 for (roff = 0; roff < num; roff++) 1379 for (col = 0; col < ri->ri_cols; col++) 1380 rasops_copychar(cookie, src + roff, dst + roff, 1381 col, col); 1382 else 1383 for (roff = num - 1; roff >= 0; roff--) 1384 for (col = 0; col < ri->ri_cols; col++) 1385 rasops_copychar(cookie, src + roff, dst + roff, 1386 col, col); 1387} 1388 1389static void 1390rasops_copycols_rotated_cw(void *cookie, int row, int src, int dst, int num) 1391{ 1392 int coff; 1393 1394 if (src > dst) 1395 for (coff = 0; coff < num; coff++) 1396 rasops_copychar(cookie, row, row, src + coff, 1397 dst + coff); 1398 else 1399 for (coff = num - 1; coff >= 0; coff--) 1400 rasops_copychar(cookie, row, row, src + coff, 1401 dst + coff); 1402} 1403 1404static void 1405rasops_eraserows_rotated_cw(void *cookie, int row, int num, long attr) 1406{ 1407 struct rasops_info *ri = (struct rasops_info *)cookie; 1408 int col, rn; 1409 1410 for (rn = row; rn < row + num; rn++) 1411 for (col = 0; col < ri->ri_cols; col++) 1412 ri->ri_ops.putchar(cookie, rn, col, ' ', attr); 1413} 1414 1415/* 1416 * Quarter counter-clockwise rotation routines (originally intended for the 1417 * built-in Sharp W-ZERO3 display in 16bpp). 1418 */ 1419static void 1420rasops_copychar_ccw(void *cookie, int srcrow, int dstrow, int srccol, 1421 int dstcol) 1422{ 1423 struct rasops_info *ri = (struct rasops_info *)cookie; 1424 int height, r_srcrow, r_dstrow, r_srccol, r_dstcol; 1425 uint8_t *sp, *dp; 1426 1427 r_srcrow = ri->ri_cols - srccol - 1; 1428 r_dstrow = ri->ri_cols - dstcol - 1; 1429 r_srccol = srcrow; 1430 r_dstcol = dstrow; 1431 1432 r_srcrow *= ri->ri_yscale; 1433 r_dstrow *= ri->ri_yscale; 1434 height = ri->ri_font->fontheight; 1435 1436 sp = ri->ri_bits + r_srcrow + r_srccol * ri->ri_xscale; 1437 dp = ri->ri_bits + r_dstrow + r_dstcol * ri->ri_xscale; 1438 1439 while (height--) { 1440 memmove(dp, sp, ri->ri_xscale); 1441 dp += ri->ri_stride; 1442 sp += ri->ri_stride; 1443 } 1444} 1445 1446static void 1447rasops_putchar_rotated_ccw(void *cookie, int row, int col, u_int uc, long attr) 1448{ 1449 struct rasops_info *ri = (struct rasops_info *)cookie; 1450 int height; 1451 uint8_t *rp; 1452 1453 if (__predict_false((unsigned int)row > ri->ri_rows || 1454 (unsigned int)col > ri->ri_cols)) 1455 return; 1456 1457 /* Avoid underflow */ 1458 if (ri->ri_cols - col - 1 < 0) 1459 return; 1460 1461 /* Do rotated char sans (side)underline */ 1462 ri->ri_real_ops.putchar(cookie, ri->ri_cols - col - 1, row, uc, 1463 attr & ~WSATTR_UNDERLINE); 1464 1465 /* Do rotated underline */ 1466 rp = ri->ri_bits + (ri->ri_cols - col - 1) * ri->ri_yscale + 1467 row * ri->ri_xscale + 1468 (ri->ri_font->fontwidth - 1) * ri->ri_pelbytes; 1469 height = ri->ri_font->fontheight; 1470 1471 /* XXX this assumes 16-bit color depth */ 1472 if ((attr & WSATTR_UNDERLINE) != 0) { 1473 uint16_t c = 1474 (uint16_t)ri->ri_devcmap[((u_int)attr >> 24) & 0xf]; 1475 1476 while (height--) { 1477 *(uint16_t *)rp = c; 1478 rp += ri->ri_stride; 1479 } 1480 } 1481} 1482 1483/* XXX: these could likely be optimised somewhat. */ 1484static void 1485rasops_copyrows_rotated_ccw(void *cookie, int src, int dst, int num) 1486{ 1487 struct rasops_info *ri = (struct rasops_info *)cookie; 1488 int col, roff; 1489 1490 if (src > dst) 1491 for (roff = 0; roff < num; roff++) 1492 for (col = 0; col < ri->ri_cols; col++) 1493 rasops_copychar_ccw(cookie, 1494 src + roff, dst + roff, col, col); 1495 else 1496 for (roff = num - 1; roff >= 0; roff--) 1497 for (col = 0; col < ri->ri_cols; col++) 1498 rasops_copychar_ccw(cookie, 1499 src + roff, dst + roff, col, col); 1500} 1501 1502static void 1503rasops_copycols_rotated_ccw(void *cookie, int row, int src, int dst, int num) 1504{ 1505 int coff; 1506 1507 if (src > dst) 1508 for (coff = 0; coff < num; coff++) 1509 rasops_copychar_ccw(cookie, row, row, 1510 src + coff, dst + coff); 1511 else 1512 for (coff = num - 1; coff >= 0; coff--) 1513 rasops_copychar_ccw(cookie, row, row, 1514 src + coff, dst + coff); 1515} 1516#endif /* NRASOPS_ROTATION */ 1517 1518void 1519rasops_make_box_chars_16(struct rasops_info *ri) 1520{ 1521 int c, i, mid; 1522 uint16_t vert_mask, hmask_left, hmask_right; 1523 uint16_t *data = (uint16_t *)ri->ri_optfont.data; 1524 1525 vert_mask = 0xc000U >> ((ri->ri_font->fontwidth >> 1) - 1); 1526 hmask_left = 0xff00U << (8 - (ri->ri_font->fontwidth >> 1)); 1527 hmask_right = hmask_left >> ((ri->ri_font->fontwidth + 1) >> 1); 1528 mid = (ri->ri_font->fontheight + 1) >> 1; 1529 1530 /* 0x00 would be empty anyway so don't bother */ 1531 for (c = 1; c < 16; c++) { 1532 data += ri->ri_font->fontheight; 1533 if (c & 1) { 1534 /* upper segment */ 1535 for (i = 0; i < mid; i++) 1536 data[i] = vert_mask; 1537 } 1538 if (c & 4) { 1539 /* lower segment */ 1540 for (i = mid; i < ri->ri_font->fontheight; i++) 1541 data[i] = vert_mask; 1542 } 1543 if (c & 2) { 1544 /* right segment */ 1545 i = ri->ri_font->fontheight >> 1; 1546 data[mid - 1] |= hmask_right; 1547 data[mid] |= hmask_right; 1548 } 1549 if (c & 8) { 1550 /* left segment */ 1551 data[mid - 1] |= hmask_left; 1552 data[mid] |= hmask_left; 1553 } 1554 } 1555} 1556 1557void 1558rasops_make_box_chars_8(struct rasops_info *ri) 1559{ 1560 int c, i, mid; 1561 uint8_t vert_mask, hmask_left, hmask_right; 1562 uint8_t *data = (uint8_t *)ri->ri_optfont.data; 1563 1564 vert_mask = 0xc0U >> ((ri->ri_font->fontwidth >> 1) - 1); 1565 hmask_left = 0xf0U << (4 - (ri->ri_font->fontwidth >> 1)); 1566 hmask_right = hmask_left >> ((ri->ri_font->fontwidth + 1) >> 1); 1567 mid = (ri->ri_font->fontheight + 1) >> 1; 1568 1569 /* 0x00 would be empty anyway so don't bother */ 1570 for (c = 1; c < 16; c++) { 1571 data += ri->ri_font->fontheight; 1572 if (c & 1) { 1573 /* upper segment */ 1574 for (i = 0; i < mid; i++) 1575 data[i] = vert_mask; 1576 } 1577 if (c & 4) { 1578 /* lower segment */ 1579 for (i = mid; i < ri->ri_font->fontheight; i++) 1580 data[i] = vert_mask; 1581 } 1582 if (c & 2) { 1583 /* right segment */ 1584 i = ri->ri_font->fontheight >> 1; 1585 data[mid - 1] |= hmask_right; 1586 data[mid] |= hmask_right; 1587 } 1588 if (c & 8) { 1589 /* left segment */ 1590 data[mid - 1] |= hmask_left; 1591 data[mid] |= hmask_left; 1592 } 1593 } 1594} 1595 1596void 1597rasops_make_box_chars_32(struct rasops_info *ri) 1598{ 1599 int c, i, mid; 1600 uint32_t vert_mask, hmask_left, hmask_right; 1601 uint32_t *data = (uint32_t *)ri->ri_optfont.data; 1602 1603 vert_mask = 0xc0000000U >> ((ri->ri_font->fontwidth >> 1) - 1); 1604 hmask_left = 0xffff0000U << (16 - (ri->ri_font->fontwidth >> 1)); 1605 hmask_right = hmask_left >> ((ri->ri_font->fontwidth + 1) >> 1); 1606 mid = (ri->ri_font->fontheight + 1) >> 1; 1607 1608 /* 0x00 would be empty anyway so don't bother */ 1609 for (c = 1; c < 16; c++) { 1610 data += ri->ri_font->fontheight; 1611 if (c & 1) { 1612 /* upper segment */ 1613 for (i = 0; i < mid; i++) 1614 data[i] = vert_mask; 1615 } 1616 if (c & 4) { 1617 /* lower segment */ 1618 for (i = mid; i < ri->ri_font->fontheight; i++) 1619 data[i] = vert_mask; 1620 } 1621 if (c & 2) { 1622 /* right segment */ 1623 i = ri->ri_font->fontheight >> 1; 1624 data[mid - 1] |= hmask_right; 1625 data[mid] |= hmask_right; 1626 } 1627 if (c & 8) { 1628 /* left segment */ 1629 data[mid - 1] |= hmask_left; 1630 data[mid] |= hmask_left; 1631 } 1632 } 1633} 1634 1635void 1636rasops_make_box_chars_alpha(struct rasops_info *ri) 1637{ 1638 int c, i, hmid, vmid, wi, he; 1639 uint8_t *data = (uint8_t *)ri->ri_optfont.data; 1640 uint8_t *ddata; 1641 1642 he = ri->ri_font->fontheight; 1643 wi = ri->ri_font->fontwidth; 1644 1645 vmid = (he + 1) >> 1; 1646 hmid = (wi + 1) >> 1; 1647 1648 /* 0x00 would be empty anyway so don't bother */ 1649 for (c = 1; c < 16; c++) { 1650 data += ri->ri_fontscale; 1651 if (c & 1) { 1652 /* upper segment */ 1653 ddata = data + hmid; 1654 for (i = 0; i <= vmid; i++) { 1655 *ddata = 0xff; 1656 ddata += wi; 1657 } 1658 } 1659 if (c & 4) { 1660 /* lower segment */ 1661 ddata = data + wi * vmid + hmid; 1662 for (i = vmid; i < he; i++) { 1663 *ddata = 0xff; 1664 ddata += wi; 1665 } 1666 } 1667 if (c & 2) { 1668 /* right segment */ 1669 ddata = data + wi * vmid + hmid; 1670 for (i = hmid; i < wi; i++) { 1671 *ddata = 0xff; 1672 ddata++; 1673 } 1674 } 1675 if (c & 8) { 1676 /* left segment */ 1677 ddata = data + wi * vmid; 1678 for (i = 0; i <= hmid; i++) { 1679 *ddata = 0xff; 1680 ddata++; 1681 } 1682 } 1683 } 1684} 1685 1686/* 1687 * Return a colour map appropriate for the given struct rasops_info in the 1688 * same form used by rasops_cmap[] 1689 * For now this is either a copy of rasops_cmap[] or an R3G3B2 map, it should 1690 * probably be a linear ( or gamma corrected? ) ramp for higher depths. 1691 */ 1692 1693int 1694rasops_get_cmap(struct rasops_info *ri, uint8_t *palette, size_t bytes) 1695{ 1696 1697 if ((ri->ri_depth == 8) && ((ri->ri_flg & RI_8BIT_IS_RGB) != 0)) { 1698 /* generate an R3G3B2 palette */ 1699 int i, idx = 0; 1700 uint8_t tmp; 1701 1702 if (bytes < 768) 1703 return EINVAL; 1704 for (i = 0; i < 256; i++) { 1705 tmp = i & 0xe0; 1706 /* 1707 * replicate bits so 0xe0 maps to a red value of 0xff 1708 * in order to make white look actually white 1709 */ 1710 tmp |= (tmp >> 3) | (tmp >> 6); 1711 palette[idx] = tmp; 1712 idx++; 1713 1714 tmp = (i & 0x1c) << 3; 1715 tmp |= (tmp >> 3) | (tmp >> 6); 1716 palette[idx] = tmp; 1717 idx++; 1718 1719 tmp = (i & 0x03) << 6; 1720 tmp |= tmp >> 2; 1721 tmp |= tmp >> 4; 1722 palette[idx] = tmp; 1723 idx++; 1724 } 1725 } else 1726 memcpy(palette, rasops_cmap, uimin(bytes, sizeof(rasops_cmap))); 1727 return 0; 1728} 1729