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