Add a note about Rockbox not running on Sansas v2 (FS#8477 by Marc Guay).
[Rockbox.git] / firmware / drivers / lcd-1bit-vert.c
blob3a6e59c46159e07c26e6c5382a70a3145550afb7
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Alan Korr
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include "config.h"
22 #include "lcd.h"
23 #include "kernel.h"
24 #include "thread.h"
25 #include <string.h>
26 #include <stdlib.h>
27 #include "file.h"
28 #include "debug.h"
29 #include "system.h"
30 #include "font.h"
31 #include "rbunicode.h"
32 #include "bidi.h"
33 #include "scroll_engine.h"
35 #ifndef LCDFN /* Not compiling for remote - define macros for main LCD. */
36 #define LCDFN(fn) lcd_ ## fn
37 #define FBFN(fn) fb_ ## fn
38 #define LCDM(ma) LCD_ ## ma
39 #define MAIN_LCD
40 #endif
42 /*** globals ***/
44 FBFN(data) LCDFN(framebuffer)[LCDM(FBHEIGHT)][LCDM(FBWIDTH)]
45 #if CONFIG_CPU != SH7034
46 IBSS_ATTR
47 #endif
50 static struct viewport default_vp =
52 .x = 0,
53 .y = 0,
54 .width = LCDM(WIDTH),
55 .height = LCDM(HEIGHT),
56 .font = FONT_SYSFIXED,
57 .drawmode = DRMODE_SOLID,
58 .xmargin = 0,
59 .ymargin = 0,
62 static struct viewport* current_vp = &default_vp;
64 /*** Viewports ***/
66 void LCDFN(set_viewport)(struct viewport* vp)
68 if (vp == NULL)
69 current_vp = &default_vp;
70 else
71 current_vp = vp;
74 void LCDFN(update_viewport)(void)
76 LCDFN(update_rect)(current_vp->x, current_vp->y,
77 current_vp->width, current_vp->height);
80 void LCDFN(update_viewport_rect)(int x, int y, int width, int height)
82 LCDFN(update_rect)(current_vp->x + x, current_vp->y + y, width, height);
85 /* LCD init */
86 void LCDFN(init)(void)
88 LCDFN(clear_display)();
89 #ifndef SIMULATOR
90 LCDFN(init_device)();
91 #endif
92 #ifdef MAIN_LCD
93 scroll_init();
94 #endif
97 /*** parameter handling ***/
99 void LCDFN(set_drawmode)(int mode)
101 current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
104 int LCDFN(get_drawmode)(void)
106 return current_vp->drawmode;
109 void LCDFN(setmargins)(int x, int y)
111 current_vp->xmargin = x;
112 current_vp->ymargin = y;
115 int LCDFN(getxmargin)(void)
117 return current_vp->xmargin;
120 int LCDFN(getymargin)(void)
122 return current_vp->ymargin;
125 int LCDFN(getwidth)(void)
127 return current_vp->width;
130 int LCDFN(getheight)(void)
132 return current_vp->height;
135 void LCDFN(setfont)(int newfont)
137 current_vp->font = newfont;
140 int LCDFN(getfont)(void)
142 return current_vp->font;
145 int LCDFN(getstringsize)(const unsigned char *str, int *w, int *h)
147 return font_getstringsize(str, w, h, current_vp->font);
150 /*** low-level drawing functions ***/
152 static void setpixel(int x, int y)
154 LCDFN(framebuffer)[y>>3][x] |= 1 << (y & 7);
157 static void clearpixel(int x, int y)
159 LCDFN(framebuffer)[y>>3][x] &= ~(1 << (y & 7));
162 static void flippixel(int x, int y)
164 LCDFN(framebuffer)[y>>3][x] ^= 1 << (y & 7);
167 static void nopixel(int x, int y)
169 (void)x;
170 (void)y;
173 LCDFN(pixelfunc_type)* const LCDFN(pixelfuncs)[8] = {
174 flippixel, nopixel, setpixel, setpixel,
175 nopixel, clearpixel, nopixel, clearpixel
178 static void ICODE_ATTR flipblock(FBFN(data) *address, unsigned mask,
179 unsigned bits)
181 *address ^= bits & mask;
184 static void ICODE_ATTR bgblock(FBFN(data) *address, unsigned mask,
185 unsigned bits)
187 *address &= bits | ~mask;
190 static void ICODE_ATTR fgblock(FBFN(data) *address, unsigned mask,
191 unsigned bits)
193 *address |= bits & mask;
196 static void ICODE_ATTR solidblock(FBFN(data) *address, unsigned mask,
197 unsigned bits)
199 unsigned data = *(char*)address;
201 bits ^= data;
202 *address = data ^ (bits & mask);
205 static void ICODE_ATTR flipinvblock(FBFN(data) *address, unsigned mask,
206 unsigned bits)
208 *address ^= ~bits & mask;
211 static void ICODE_ATTR bginvblock(FBFN(data) *address, unsigned mask,
212 unsigned bits)
214 *address &= ~(bits & mask);
217 static void ICODE_ATTR fginvblock(FBFN(data) *address, unsigned mask,
218 unsigned bits)
220 *address |= ~bits & mask;
223 static void ICODE_ATTR solidinvblock(FBFN(data) *address, unsigned mask,
224 unsigned bits)
226 unsigned data = *(char *)address;
228 bits = ~bits ^ data;
229 *address = data ^ (bits & mask);
232 LCDFN(blockfunc_type)* const LCDFN(blockfuncs)[8] = {
233 flipblock, bgblock, fgblock, solidblock,
234 flipinvblock, bginvblock, fginvblock, solidinvblock
237 /*** drawing functions ***/
239 /* Clear the whole display */
240 void LCDFN(clear_display)(void)
242 unsigned bits = (current_vp->drawmode & DRMODE_INVERSEVID) ? 0xFFu : 0;
244 memset(LCDFN(framebuffer), bits, sizeof LCDFN(framebuffer));
245 LCDFN(scroll_info).lines = 0;
248 /* Clear the current viewport */
249 void LCDFN(clear_viewport)(void)
251 int oldmode;
253 if (current_vp == &default_vp)
255 LCDFN(clear_display)();
257 else
259 oldmode = current_vp->drawmode;
261 /* Invert the INVERSEVID bit and set basic mode to SOLID */
262 current_vp->drawmode = (~current_vp->drawmode & DRMODE_INVERSEVID) |
263 DRMODE_SOLID;
265 LCDFN(fillrect)(0, 0, current_vp->width, current_vp->height);
267 current_vp->drawmode = oldmode;
269 LCDFN(scroll_stop)(current_vp);
273 /* Set a single pixel */
274 void LCDFN(drawpixel)(int x, int y)
276 if (((unsigned)x < (unsigned)current_vp->width) &&
277 ((unsigned)y < (unsigned)current_vp->height))
278 LCDFN(pixelfuncs)[current_vp->drawmode](current_vp->x + x, current_vp->y + y);
281 /* Draw a line */
282 void LCDFN(drawline)(int x1, int y1, int x2, int y2)
284 int numpixels;
285 int i;
286 int deltax, deltay;
287 int d, dinc1, dinc2;
288 int x, xinc1, xinc2;
289 int y, yinc1, yinc2;
290 LCDFN(pixelfunc_type) *pfunc = LCDFN(pixelfuncs)[current_vp->drawmode];
292 deltax = abs(x2 - x1);
293 deltay = abs(y2 - y1);
294 xinc2 = 1;
295 yinc2 = 1;
297 if (deltax >= deltay)
299 numpixels = deltax;
300 d = 2 * deltay - deltax;
301 dinc1 = deltay * 2;
302 dinc2 = (deltay - deltax) * 2;
303 xinc1 = 1;
304 yinc1 = 0;
306 else
308 numpixels = deltay;
309 d = 2 * deltax - deltay;
310 dinc1 = deltax * 2;
311 dinc2 = (deltax - deltay) * 2;
312 xinc1 = 0;
313 yinc1 = 1;
315 numpixels++; /* include endpoints */
317 if (x1 > x2)
319 xinc1 = -xinc1;
320 xinc2 = -xinc2;
323 if (y1 > y2)
325 yinc1 = -yinc1;
326 yinc2 = -yinc2;
329 x = x1;
330 y = y1;
332 for (i = 0; i < numpixels; i++)
334 if (((unsigned)x < (unsigned)current_vp->width)
335 && ((unsigned)y < (unsigned)current_vp->height))
336 pfunc(current_vp->x + x, current_vp->y + y);
338 if (d < 0)
340 d += dinc1;
341 x += xinc1;
342 y += yinc1;
344 else
346 d += dinc2;
347 x += xinc2;
348 y += yinc2;
353 /* Draw a horizontal line (optimised) */
354 void LCDFN(hline)(int x1, int x2, int y)
356 int x, width;
357 unsigned char *dst, *dst_end;
358 unsigned mask;
359 LCDFN(blockfunc_type) *bfunc;
361 /* direction flip */
362 if (x2 < x1)
364 x = x1;
365 x1 = x2;
366 x2 = x;
369 /* nothing to draw? */
370 if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width)
371 || (x2 < 0))
372 return;
374 /* clipping */
375 if (x1 < 0)
376 x1 = 0;
377 if (x2 >= current_vp->width)
378 x2 = current_vp->width-1;
380 width = x2 - x1 + 1;
382 /* adjust to viewport */
383 x1 += current_vp->x;
384 y += current_vp->y;
386 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
387 dst = &LCDFN(framebuffer)[y>>3][x1];
388 mask = 1 << (y & 7);
390 dst_end = dst + width;
392 bfunc(dst++, mask, 0xFFu);
393 while (dst < dst_end);
396 /* Draw a vertical line (optimised) */
397 void LCDFN(vline)(int x, int y1, int y2)
399 int ny;
400 FBFN(data) *dst;
401 unsigned mask, mask_bottom;
402 LCDFN(blockfunc_type) *bfunc;
404 /* direction flip */
405 if (y2 < y1)
407 ny = y1;
408 y1 = y2;
409 y2 = ny;
412 /* nothing to draw? */
413 if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height)
414 || (y2 < 0))
415 return;
417 /* clipping */
418 if (y1 < 0)
419 y1 = 0;
420 if (y2 >= current_vp->height)
421 y2 = current_vp->height-1;
423 /* adjust for viewport */
424 y1 += current_vp->y;
425 y2 += current_vp->y;
426 x += current_vp->x;
428 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
429 dst = &LCDFN(framebuffer)[y1>>3][x];
430 ny = y2 - (y1 & ~7);
431 mask = 0xFFu << (y1 & 7);
432 mask_bottom = 0xFFu >> (~ny & 7);
434 for (; ny >= 8; ny -= 8)
436 bfunc(dst, mask, 0xFFu);
437 dst += LCDM(WIDTH);
438 mask = 0xFFu;
440 mask &= mask_bottom;
441 bfunc(dst, mask, 0xFFu);
444 /* Draw a rectangular box */
445 void LCDFN(drawrect)(int x, int y, int width, int height)
447 if ((width <= 0) || (height <= 0))
448 return;
450 int x2 = x + width - 1;
451 int y2 = y + height - 1;
453 LCDFN(vline)(x, y, y2);
454 LCDFN(vline)(x2, y, y2);
455 LCDFN(hline)(x, x2, y);
456 LCDFN(hline)(x, x2, y2);
459 /* Fill a rectangular area */
460 void LCDFN(fillrect)(int x, int y, int width, int height)
462 int ny;
463 FBFN(data) *dst, *dst_end;
464 unsigned mask, mask_bottom;
465 unsigned bits = 0;
466 LCDFN(blockfunc_type) *bfunc;
467 bool fillopt = false;
469 /* nothing to draw? */
470 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
471 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
472 return;
474 /* clipping */
475 if (x < 0)
477 width += x;
478 x = 0;
480 if (y < 0)
482 height += y;
483 y = 0;
485 if (x + width > current_vp->width)
486 width = current_vp->width - x;
487 if (y + height > current_vp->height)
488 height = current_vp->height - y;
490 /* adjust for viewport */
491 x += current_vp->x;
492 y += current_vp->y;
494 if (current_vp->drawmode & DRMODE_INVERSEVID)
496 if (current_vp->drawmode & DRMODE_BG)
498 fillopt = true;
501 else
503 if (current_vp->drawmode & DRMODE_FG)
505 fillopt = true;
506 bits = 0xFFu;
509 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
510 dst = &LCDFN(framebuffer)[y>>3][x];
511 ny = height - 1 + (y & 7);
512 mask = 0xFFu << (y & 7);
513 mask_bottom = 0xFFu >> (~ny & 7);
515 for (; ny >= 8; ny -= 8)
517 if (fillopt && (mask == 0xFFu))
518 memset(dst, bits, width);
519 else
521 FBFN(data) *dst_row = dst;
523 dst_end = dst_row + width;
525 bfunc(dst_row++, mask, 0xFFu);
526 while (dst_row < dst_end);
529 dst += LCDM(WIDTH);
530 mask = 0xFFu;
532 mask &= mask_bottom;
534 if (fillopt && (mask == 0xFFu))
535 memset(dst, bits, width);
536 else
538 dst_end = dst + width;
540 bfunc(dst++, mask, 0xFFu);
541 while (dst < dst_end);
545 /* About Rockbox' internal bitmap format:
547 * A bitmap contains one bit for every pixel that defines if that pixel is
548 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
549 * at top.
550 * The bytes are stored in row-major order, with byte 0 being top left,
551 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
552 * 0..7, the second row defines pixel row 8..15 etc.
554 * This is the same as the internal lcd hw format. */
556 /* Draw a partial bitmap */
557 void ICODE_ATTR LCDFN(bitmap_part)(const unsigned char *src, int src_x,
558 int src_y, int stride, int x, int y,
559 int width, int height)
561 int shift, ny;
562 FBFN(data) *dst, *dst_end;
563 unsigned mask, mask_bottom;
564 LCDFN(blockfunc_type) *bfunc;
566 /* nothing to draw? */
567 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
568 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
569 return;
571 /* clipping */
572 if (x < 0)
574 width += x;
575 src_x -= x;
576 x = 0;
578 if (y < 0)
580 height += y;
581 src_y -= y;
582 y = 0;
584 if (x + width > current_vp->width)
585 width = current_vp->width - x;
586 if (y + height > current_vp->height)
587 height = current_vp->height - y;
589 /* adjust for viewport */
590 x += current_vp->x;
591 y += current_vp->y;
593 src += stride * (src_y >> 3) + src_x; /* move starting point */
594 src_y &= 7;
595 y -= src_y;
596 dst = &LCDFN(framebuffer)[y>>3][x];
597 shift = y & 7;
598 ny = height - 1 + shift + src_y;
600 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
601 mask = 0xFFu << (shift + src_y);
602 mask_bottom = 0xFFu >> (~ny & 7);
604 if (shift == 0)
606 bool copyopt = (current_vp->drawmode == DRMODE_SOLID);
608 for (; ny >= 8; ny -= 8)
610 if (copyopt && (mask == 0xFFu))
611 memcpy(dst, src, width);
612 else
614 const unsigned char *src_row = src;
615 FBFN(data) *dst_row = dst;
617 dst_end = dst_row + width;
619 bfunc(dst_row++, mask, *src_row++);
620 while (dst_row < dst_end);
623 src += stride;
624 dst += LCDM(WIDTH);
625 mask = 0xFFu;
627 mask &= mask_bottom;
629 if (copyopt && (mask == 0xFFu))
630 memcpy(dst, src, width);
631 else
633 dst_end = dst + width;
635 bfunc(dst++, mask, *src++);
636 while (dst < dst_end);
639 else
641 dst_end = dst + width;
644 const unsigned char *src_col = src++;
645 FBFN(data) *dst_col = dst++;
646 unsigned mask_col = mask;
647 unsigned data = 0;
649 for (y = ny; y >= 8; y -= 8)
651 data |= *src_col << shift;
653 if (mask_col & 0xFFu)
655 bfunc(dst_col, mask_col, data);
656 mask_col = 0xFFu;
658 else
659 mask_col >>= 8;
661 src_col += stride;
662 dst_col += LCDM(WIDTH);
663 data >>= 8;
665 data |= *src_col << shift;
666 bfunc(dst_col, mask_col & mask_bottom, data);
668 while (dst < dst_end);
672 /* Draw a full bitmap */
673 void LCDFN(bitmap)(const unsigned char *src, int x, int y, int width,
674 int height)
676 LCDFN(bitmap_part)(src, 0, 0, width, x, y, width, height);
679 /* put a string at a given pixel position, skipping first ofs pixel columns */
680 static void LCDFN(putsxyofs)(int x, int y, int ofs, const unsigned char *str)
682 unsigned short ch;
683 unsigned short *ucs;
684 struct font* pf = font_get(current_vp->font);
686 ucs = bidi_l2v(str, 1);
688 while ((ch = *ucs++) != 0 && x < current_vp->width)
690 int width;
691 const unsigned char *bits;
693 /* get proportional width and glyph bits */
694 width = font_get_width(pf, ch);
696 if (ofs > width)
698 ofs -= width;
699 continue;
702 bits = font_get_bits(pf, ch);
704 LCDFN(mono_bitmap_part)(bits, ofs, 0, width, x, y, width - ofs,
705 pf->height);
707 x += width - ofs;
708 ofs = 0;
711 /* put a string at a given pixel position */
712 void LCDFN(putsxy)(int x, int y, const unsigned char *str)
714 LCDFN(putsxyofs)(x, y, 0, str);
717 /*** Line oriented text output ***/
719 /* put a string at a given char position */
720 void LCDFN(puts)(int x, int y, const unsigned char *str)
722 LCDFN(puts_style_offset)(x, y, str, STYLE_DEFAULT, 0);
725 void LCDFN(puts_style)(int x, int y, const unsigned char *str, int style)
727 LCDFN(puts_style_offset)(x, y, str, style, 0);
730 void LCDFN(puts_offset)(int x, int y, const unsigned char *str, int offset)
732 LCDFN(puts_style_offset)(x, y, str, STYLE_DEFAULT, offset);
735 /* put a string at a given char position, style, and pixel position,
736 * skipping first offset pixel columns */
737 void LCDFN(puts_style_offset)(int x, int y, const unsigned char *str,
738 int style, int offset)
740 int xpos,ypos,w,h,xrect;
741 int lastmode = current_vp->drawmode;
743 /* make sure scrolling is turned off on the line we are updating */
744 LCDFN(scroll_stop_line)(current_vp, y);
746 if(!str || !str[0])
747 return;
749 LCDFN(getstringsize)(str, &w, &h);
750 xpos = current_vp->xmargin + x*w / utf8length(str);
751 ypos = current_vp->ymargin + y*h;
752 current_vp->drawmode = (style & STYLE_INVERT) ?
753 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
754 LCDFN(putsxyofs)(xpos, ypos, offset, str);
755 current_vp->drawmode ^= DRMODE_INVERSEVID;
756 xrect = xpos + MAX(w - offset, 0);
757 LCDFN(fillrect)(xrect, ypos, current_vp->width - xrect, h);
758 current_vp->drawmode = lastmode;
761 /*** scrolling ***/
763 void LCDFN(puts_scroll)(int x, int y, const unsigned char *string)
765 LCDFN(puts_scroll_style)(x, y, string, STYLE_DEFAULT);
768 void LCDFN(puts_scroll_style)(int x, int y, const unsigned char *string,
769 int style)
771 LCDFN(puts_scroll_style_offset)(x, y, string, style, 0);
774 void LCDFN(puts_scroll_offset)(int x, int y, const unsigned char *string,
775 int offset)
777 LCDFN(puts_scroll_style_offset)(x, y, string, STYLE_DEFAULT, offset);
780 void LCDFN(puts_scroll_style_offset)(int x, int y, const unsigned char *string,
781 int style, int offset)
783 struct scrollinfo* s;
784 int w, h;
786 if ((unsigned)y >= (unsigned)current_vp->height)
787 return;
789 /* remove any previously scrolling line at the same location */
790 LCDFN(scroll_stop_line)(current_vp, y);
792 if (LCDFN(scroll_info.lines) >= LCDM(SCROLLABLE_LINES)) return;
794 s = &LCDFN(scroll_info).scroll[LCDFN(scroll_info).lines];
796 s->start_tick = current_tick + LCDFN(scroll_info).delay;
797 s->style = style;
798 if (style & STYLE_INVERT) {
799 LCDFN(puts_style_offset)(x,y,string,STYLE_INVERT,offset);
801 else
802 LCDFN(puts_offset)(x,y,string,offset);
804 LCDFN(getstringsize)(string, &w, &h);
806 if (current_vp->width - x * 8 - current_vp->xmargin < w) {
807 /* prepare scroll line */
808 char *end;
810 memset(s->line, 0, sizeof s->line);
811 strcpy(s->line, string);
813 /* get width */
814 s->width = LCDFN(getstringsize)(s->line, &w, &h);
816 /* scroll bidirectional or forward only depending on the string
817 width */
818 if ( LCDFN(scroll_info).bidir_limit ) {
819 s->bidir = s->width < (current_vp->width - current_vp->xmargin) *
820 (100 + LCDFN(scroll_info).bidir_limit) / 100;
822 else
823 s->bidir = false;
825 if (!s->bidir) { /* add spaces if scrolling in the round */
826 strcat(s->line, " ");
827 /* get new width incl. spaces */
828 s->width = LCDFN(getstringsize)(s->line, &w, &h);
831 end = strchr(s->line, '\0');
832 strncpy(end, string, current_vp->width/2);
834 s->vp = current_vp;
835 s->y = y;
836 s->len = utf8length(string);
837 s->offset = offset;
838 s->startx = current_vp->xmargin + x * s->width / s->len;;
839 s->backward = false;
841 LCDFN(scroll_info).lines++;
845 void LCDFN(scroll_fn)(void)
847 struct font* pf;
848 struct scrollinfo* s;
849 int index;
850 int xpos, ypos;
851 int lastmode;
852 struct viewport* old_vp = current_vp;
854 for ( index = 0; index < LCDFN(scroll_info).lines; index++ ) {
855 s = &LCDFN(scroll_info).scroll[index];
857 /* check pause */
858 if (TIME_BEFORE(current_tick, s->start_tick))
859 continue;
861 LCDFN(set_viewport)(s->vp);
863 if (s->backward)
864 s->offset -= LCDFN(scroll_info).step;
865 else
866 s->offset += LCDFN(scroll_info).step;
868 pf = font_get(current_vp->font);
869 xpos = s->startx;
870 ypos = current_vp->ymargin + s->y * pf->height;
872 if (s->bidir) { /* scroll bidirectional */
873 if (s->offset <= 0) {
874 /* at beginning of line */
875 s->offset = 0;
876 s->backward = false;
877 s->start_tick = current_tick + LCDFN(scroll_info).delay * 2;
879 if (s->offset >= s->width - (current_vp->width - xpos)) {
880 /* at end of line */
881 s->offset = s->width - (current_vp->width - xpos);
882 s->backward = true;
883 s->start_tick = current_tick + LCDFN(scroll_info).delay * 2;
886 else {
887 /* scroll forward the whole time */
888 if (s->offset >= s->width)
889 s->offset %= s->width;
892 lastmode = current_vp->drawmode;
893 current_vp->drawmode = (s->style&STYLE_INVERT) ?
894 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
895 LCDFN(putsxyofs)(xpos, ypos, s->offset, s->line);
896 current_vp->drawmode = lastmode;
897 LCDFN(update_viewport_rect)(xpos, ypos, current_vp->width - xpos, pf->height);
900 LCDFN(set_viewport)(old_vp);