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