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