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