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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 | |