Subversion Repositories HelenOS

Rev

Rev 4678 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 2008 Martin Decky
  3.  * Copyright (c) 2006 Jakub Vana
  4.  * Copyright (c) 2006 Ondrej Palkovsky
  5.  * All rights reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  *
  11.  * - Redistributions of source code must retain the above copyright
  12.  *   notice, this list of conditions and the following disclaimer.
  13.  * - Redistributions in binary form must reproduce the above copyright
  14.  *   notice, this list of conditions and the following disclaimer in the
  15.  *   documentation and/or other materials provided with the distribution.
  16.  * - The name of the author may not be used to endorse or promote products
  17.  *   derived from this software without specific prior written permission.
  18.  *
  19.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  20.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  21.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  22.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  23.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  24.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  28.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29.  */
  30.  
  31. /**
  32.  * @defgroup fb Graphical framebuffer
  33.  * @brief HelenOS graphical framebuffer.
  34.  * @ingroup fbs
  35.  * @{
  36.  */
  37.  
  38. /** @file
  39.  */
  40.  
  41. #include <stdlib.h>
  42. #include <unistd.h>
  43. #include <string.h>
  44. #include <ddi.h>
  45. #include <sysinfo.h>
  46. #include <align.h>
  47. #include <as.h>
  48. #include <ipc/fb.h>
  49. #include <ipc/ipc.h>
  50. #include <ipc/ns.h>
  51. #include <ipc/services.h>
  52. #include <kernel/errno.h>
  53. #include <kernel/genarch/fb/visuals.h>
  54. #include <io/color.h>
  55. #include <io/style.h>
  56. #include <async.h>
  57. #include <fibril.h>
  58. #include <bool.h>
  59. #include <stdio.h>
  60. #include <byteorder.h>
  61.  
  62. #include "font-8x16.h"
  63. #include "fb.h"
  64. #include "main.h"
  65. #include "../console/screenbuffer.h"
  66. #include "ppm.h"
  67.  
  68. #include "pointer.xbm"
  69. #include "pointer_mask.xbm"
  70.  
  71. #define DEFAULT_BGCOLOR  0xf0f0f0
  72. #define DEFAULT_FGCOLOR  0x000000
  73.  
  74. #define GLYPH_UNAVAIL    '?'
  75.  
  76. #define MAX_ANIM_LEN     8
  77. #define MAX_ANIMATIONS   4
  78. #define MAX_PIXMAPS      256  /**< Maximum number of saved pixmaps */
  79. #define MAX_VIEWPORTS    128  /**< Viewport is a rectangular area on the screen */
  80.  
  81. /** Function to render a pixel from a RGB value. */
  82. typedef void (*rgb_conv_t)(void *, uint32_t);
  83.  
  84. /** Function to render a bit mask. */
  85. typedef void (*mask_conv_t)(void *, bool);
  86.  
  87. /** Function to draw a glyph. */
  88. typedef void (*dg_t)(unsigned int x, unsigned int y, bool cursor,
  89.     uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color);
  90.  
  91. struct {
  92.     uint8_t *fb_addr;
  93.    
  94.     unsigned int xres;
  95.     unsigned int yres;
  96.    
  97.     unsigned int scanline;
  98.     unsigned int glyphscanline;
  99.    
  100.     unsigned int pixelbytes;
  101.     unsigned int glyphbytes;
  102.    
  103.     /** Pre-rendered mask for rendering glyphs. Specific for the visual. */
  104.     uint8_t *glyphs;
  105.    
  106.     rgb_conv_t rgb_conv;
  107.     mask_conv_t mask_conv;
  108. } screen;
  109.  
  110. /** Backbuffer character cell. */
  111. typedef struct {
  112.     uint32_t glyph;
  113.     uint32_t fg_color;
  114.     uint32_t bg_color;
  115. } bb_cell_t;
  116.  
  117. typedef struct {
  118.     bool initialized;
  119.     unsigned int x;
  120.     unsigned int y;
  121.     unsigned int width;
  122.     unsigned int height;
  123.    
  124.     /* Text support in window */
  125.     unsigned int cols;
  126.     unsigned int rows;
  127.    
  128.     /*
  129.      * Style and glyphs for text printing
  130.      */
  131.    
  132.     /** Current attributes. */
  133.     attr_rgb_t attr;
  134.    
  135.     uint8_t *bgpixel;
  136.    
  137.     /**
  138.      * Glyph drawing function for this viewport.  Different viewports
  139.      * might use different drawing functions depending on whether their
  140.      * scanlines are aligned on a word boundary.
  141.      */
  142.     dg_t dglyph;
  143.    
  144.     /* Auto-cursor position */
  145.     bool cursor_active;
  146.     unsigned int cur_col;
  147.     unsigned int cur_row;
  148.     bool cursor_shown;
  149.    
  150.     /* Back buffer */
  151.     bb_cell_t *backbuf;
  152.     unsigned int bbsize;
  153. } viewport_t;
  154.  
  155. typedef struct {
  156.     bool initialized;
  157.     bool enabled;
  158.     unsigned int vp;
  159.    
  160.     unsigned int pos;
  161.     unsigned int animlen;
  162.     unsigned int pixmaps[MAX_ANIM_LEN];
  163. } animation_t;
  164.  
  165. static animation_t animations[MAX_ANIMATIONS];
  166. static bool anims_enabled;
  167.  
  168. typedef struct {
  169.     unsigned int width;
  170.     unsigned int height;
  171.     uint8_t *data;
  172. } pixmap_t;
  173.  
  174. static pixmap_t pixmaps[MAX_PIXMAPS];
  175. static viewport_t viewports[128];
  176.  
  177. static bool client_connected = false;  /**< Allow only 1 connection */
  178.  
  179. static uint32_t color_table[16] = {
  180.     [COLOR_BLACK]       = 0x000000,
  181.     [COLOR_BLUE]        = 0x0000f0,
  182.     [COLOR_GREEN]       = 0x00f000,
  183.     [COLOR_CYAN]        = 0x00f0f0,
  184.     [COLOR_RED]         = 0xf00000,
  185.     [COLOR_MAGENTA]     = 0xf000f0,
  186.     [COLOR_YELLOW]      = 0xf0f000,
  187.     [COLOR_WHITE]       = 0xf0f0f0,
  188.    
  189.     [8 + COLOR_BLACK]   = 0x000000,
  190.     [8 + COLOR_BLUE]    = 0x0000ff,
  191.     [8 + COLOR_GREEN]   = 0x00ff00,
  192.     [8 + COLOR_CYAN]    = 0x00ffff,
  193.     [8 + COLOR_RED]     = 0xff0000,
  194.     [8 + COLOR_MAGENTA] = 0xff00ff,
  195.     [8 + COLOR_YELLOW]  = 0xffff00,
  196.     [8 + COLOR_WHITE]   = 0xffffff,
  197. };
  198.  
  199. static int rgb_from_attr(attr_rgb_t *rgb, const attrs_t *a);
  200. static int rgb_from_style(attr_rgb_t *rgb, int style);
  201. static int rgb_from_idx(attr_rgb_t *rgb, ipcarg_t fg_color,
  202.     ipcarg_t bg_color, ipcarg_t flags);
  203.  
  204. static int fb_set_color(viewport_t *vport, ipcarg_t fg_color,
  205.     ipcarg_t bg_color, ipcarg_t attr);
  206.  
  207. static void draw_glyph_aligned(unsigned int x, unsigned int y, bool cursor,
  208.     uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color);
  209. static void draw_glyph_fallback(unsigned int x, unsigned int y, bool cursor,
  210.     uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color);
  211.  
  212. static void draw_vp_glyph(viewport_t *vport, bool cursor, unsigned int col,
  213.     unsigned int row);
  214.  
  215.  
  216. #define RED(x, bits)                 (((x) >> (8 + 8 + 8 - (bits))) & ((1 << (bits)) - 1))
  217. #define GREEN(x, bits)               (((x) >> (8 + 8 - (bits))) & ((1 << (bits)) - 1))
  218. #define BLUE(x, bits)                (((x) >> (8 - (bits))) & ((1 << (bits)) - 1))
  219.  
  220. #define COL2X(col)                   ((col) * FONT_WIDTH)
  221. #define ROW2Y(row)                   ((row) * FONT_SCANLINES)
  222.  
  223. #define X2COL(x)                     ((x) / FONT_WIDTH)
  224. #define Y2ROW(y)                     ((y) / FONT_SCANLINES)
  225.  
  226. #define FB_POS(x, y)                 ((y) * screen.scanline + (x) * screen.pixelbytes)
  227. #define BB_POS(vport, col, row)      ((row) * vport->cols + (col))
  228. #define GLYPH_POS(glyph, y, cursor)  (((glyph) + (cursor) * FONT_GLYPHS) * screen.glyphbytes + (y) * screen.glyphscanline)
  229.  
  230. /*
  231.  * RGB conversion and mask functions.
  232.  *
  233.  * These functions write an RGB value to some memory in some predefined format.
  234.  * The naming convention corresponds to the format created by these functions.
  235.  * The functions use the so called network order (i.e. big endian) with respect
  236.  * to their names.
  237.  */
  238.  
  239. static void rgb_0888(void *dst, uint32_t rgb)
  240. {
  241.     *((uint32_t *) dst) = host2uint32_t_be((0 << 24) |
  242.         (RED(rgb, 8) << 16) | (GREEN(rgb, 8) << 8) | (BLUE(rgb, 8)));
  243. }
  244.  
  245. static void bgr_0888(void *dst, uint32_t rgb)
  246. {
  247.     *((uint32_t *) dst) = host2uint32_t_be((0 << 24) |
  248.         (BLUE(rgb, 8) << 16) | (GREEN(rgb, 8) << 8) | (RED(rgb, 8)));
  249. }
  250.  
  251. static void mask_0888(void *dst, bool mask)
  252. {
  253.     bgr_0888(dst, mask ? 0xffffff : 0);
  254. }
  255.  
  256. static void rgb_8880(void *dst, uint32_t rgb)
  257. {
  258.     *((uint32_t *) dst) = host2uint32_t_be((RED(rgb, 8) << 24) |
  259.         (GREEN(rgb, 8) << 16) | (BLUE(rgb, 8) << 8) | 0);
  260. }
  261.  
  262. static void bgr_8880(void *dst, uint32_t rgb)
  263. {
  264.     *((uint32_t *) dst) = host2uint32_t_be((BLUE(rgb, 8) << 24) |
  265.         (GREEN(rgb, 8) << 16) | (RED(rgb, 8) << 8) | 0);
  266. }
  267.  
  268. static void mask_8880(void *dst, bool mask)
  269. {
  270.     bgr_8880(dst, mask ? 0xffffff : 0);
  271. }
  272.  
  273. static void rgb_888(void *dst, uint32_t rgb)
  274. {
  275.     ((uint8_t *) dst)[0] = RED(rgb, 8);
  276.     ((uint8_t *) dst)[1] = GREEN(rgb, 8);
  277.     ((uint8_t *) dst)[2] = BLUE(rgb, 8);
  278. }
  279.  
  280. static void bgr_888(void *dst, uint32_t rgb)
  281. {
  282.     ((uint8_t *) dst)[0] = BLUE(rgb, 8);
  283.     ((uint8_t *) dst)[1] = GREEN(rgb, 8);
  284.     ((uint8_t *) dst)[2] = RED(rgb, 8);
  285. }
  286.  
  287. static void mask_888(void *dst, bool mask)
  288. {
  289.     bgr_888(dst, mask ? 0xffffff : 0);
  290. }
  291.  
  292. static void rgb_555_be(void *dst, uint32_t rgb)
  293. {
  294.     *((uint16_t *) dst) = host2uint16_t_be(RED(rgb, 5) << 10 |
  295.         GREEN(rgb, 5) << 5 | BLUE(rgb, 5));
  296. }
  297.  
  298. static void rgb_555_le(void *dst, uint32_t rgb)
  299. {
  300.     *((uint16_t *) dst) = host2uint16_t_le(RED(rgb, 5) << 10 |
  301.         GREEN(rgb, 5) << 5 | BLUE(rgb, 5));
  302. }
  303.  
  304. static void rgb_565_be(void *dst, uint32_t rgb)
  305. {
  306.     *((uint16_t *) dst) = host2uint16_t_be(RED(rgb, 5) << 11 |
  307.         GREEN(rgb, 6) << 5 | BLUE(rgb, 5));
  308. }
  309.  
  310. static void rgb_565_le(void *dst, uint32_t rgb)
  311. {
  312.     *((uint16_t *) dst) = host2uint16_t_le(RED(rgb, 5) << 11 |
  313.         GREEN(rgb, 6) << 5 | BLUE(rgb, 5));
  314. }
  315.  
  316. static void mask_555(void *dst, bool mask)
  317. {
  318.     rgb_555_be(dst, mask ? 0xffffff : 0);
  319. }
  320.  
  321. static void mask_565(void *dst, bool mask)
  322. {
  323.     rgb_565_be(dst, mask ? 0xffffff : 0);
  324. }
  325.  
  326. static void bgr_323(void *dst, uint32_t rgb)
  327. {
  328.     *((uint8_t *) dst)
  329.         = ~((RED(rgb, 3) << 5) | (GREEN(rgb, 2) << 3) | BLUE(rgb, 3));
  330. }
  331.  
  332. static void mask_323(void *dst, bool mask)
  333. {
  334.     bgr_323(dst, mask ? 0x0 : ~0x0);
  335. }
  336.  
  337. /** Draw a filled rectangle.
  338.  *
  339.  * @note Need real implementation that does not access VRAM twice.
  340.  *
  341.  */
  342. static void draw_filled_rect(unsigned int x0, unsigned int y0, unsigned int x1,
  343.     unsigned int y1, uint32_t color)
  344. {
  345.     unsigned int x;
  346.     unsigned int y;
  347.     unsigned int copy_bytes;
  348.    
  349.     uint8_t *sp;
  350.     uint8_t *dp;
  351.     uint8_t cbuf[4];
  352.    
  353.     if ((y0 >= y1) || (x0 >= x1))
  354.         return;
  355.    
  356.     screen.rgb_conv(cbuf, color);
  357.    
  358.     sp = &screen.fb_addr[FB_POS(x0, y0)];
  359.     dp = sp;
  360.    
  361.     /* Draw the first line. */
  362.     for (x = x0; x < x1; x++) {
  363.         memcpy(dp, cbuf, screen.pixelbytes);
  364.         dp += screen.pixelbytes;
  365.     }
  366.    
  367.     dp = sp + screen.scanline;
  368.     copy_bytes = (x1 - x0) * screen.pixelbytes;
  369.    
  370.     /* Draw the remaining lines by copying. */
  371.     for (y = y0 + 1; y < y1; y++) {
  372.         memcpy(dp, sp, copy_bytes);
  373.         dp += screen.scanline;
  374.     }
  375. }
  376.  
  377. /** Redraw viewport.
  378.  *
  379.  * @param vport Viewport to redraw
  380.  *
  381.  */
  382. static void vport_redraw(viewport_t *vport)
  383. {
  384.     unsigned int col;
  385.     unsigned int row;
  386.    
  387.     for (row = 0; row < vport->rows; row++) {
  388.         for (col = 0; col < vport->cols; col++) {
  389.             draw_vp_glyph(vport, false, col, row);
  390.         }
  391.     }
  392.    
  393.     if (COL2X(vport->cols) < vport->width) {
  394.         draw_filled_rect(
  395.             vport->x + COL2X(vport->cols), vport->y,
  396.             vport->x + vport->width, vport->y + vport->height,
  397.             vport->attr.bg_color);
  398.     }
  399.    
  400.     if (ROW2Y(vport->rows) < vport->height) {
  401.         draw_filled_rect(
  402.             vport->x, vport->y + ROW2Y(vport->rows),
  403.             vport->x + vport->width, vport->y + vport->height,
  404.             vport->attr.bg_color);
  405.     }
  406. }
  407.  
  408. static void backbuf_clear(bb_cell_t *backbuf, size_t len, uint32_t fg_color,
  409.     uint32_t bg_color)
  410. {
  411.     size_t i;
  412.    
  413.     for (i = 0; i < len; i++) {
  414.         backbuf[i].glyph = 0;
  415.         backbuf[i].fg_color = fg_color;
  416.         backbuf[i].bg_color = bg_color;
  417.     }
  418. }
  419.  
  420. /** Clear viewport.
  421.  *
  422.  * @param vport Viewport to clear
  423.  *
  424.  */
  425. static void vport_clear(viewport_t *vport)
  426. {
  427.     backbuf_clear(vport->backbuf, vport->cols * vport->rows,
  428.         vport->attr.fg_color, vport->attr.bg_color);
  429.     vport_redraw(vport);
  430. }
  431.  
  432. /** Scroll viewport by the specified number of lines.
  433.  *
  434.  * @param vport Viewport to scroll
  435.  * @param lines Number of lines to scroll
  436.  *
  437.  */
  438. static void vport_scroll(viewport_t *vport, int lines)
  439. {
  440.     unsigned int col;
  441.     unsigned int row;
  442.     unsigned int x;
  443.     unsigned int y;
  444.     uint32_t glyph;
  445.     uint32_t fg_color;
  446.     uint32_t bg_color;
  447.     bb_cell_t *bbp;
  448.     bb_cell_t *xbp;
  449.    
  450.     /*
  451.      * Redraw.
  452.      */
  453.    
  454.     y = vport->y;
  455.     for (row = 0; row < vport->rows; row++) {
  456.         x = vport->x;
  457.         for (col = 0; col < vport->cols; col++) {
  458.             if (((int) row + lines >= 0) &&
  459.                 ((int) row + lines < (int) vport->rows)) {
  460.                 xbp = &vport->backbuf[BB_POS(vport, col, row + lines)];
  461.                 bbp = &vport->backbuf[BB_POS(vport, col, row)];
  462.                
  463.                 glyph = xbp->glyph;
  464.                 fg_color = xbp->fg_color;
  465.                 bg_color = xbp->bg_color;
  466.                
  467.                 if ((bbp->glyph == glyph)
  468.                    && (bbp->fg_color == xbp->fg_color)
  469.                    && (bbp->bg_color == xbp->bg_color)) {
  470.                     x += FONT_WIDTH;
  471.                     continue;
  472.                 }
  473.             } else {
  474.                 glyph = 0;
  475.                 fg_color = vport->attr.fg_color;
  476.                 bg_color = vport->attr.bg_color;
  477.             }
  478.            
  479.             (*vport->dglyph)(x, y, false, screen.glyphs, glyph,
  480.                 fg_color, bg_color);
  481.             x += FONT_WIDTH;
  482.         }
  483.         y += FONT_SCANLINES;
  484.     }
  485.    
  486.     /*
  487.      * Scroll backbuffer.
  488.      */
  489.    
  490.     if (lines > 0) {
  491.         memmove(vport->backbuf, vport->backbuf + vport->cols * lines,
  492.             vport->cols * (vport->rows - lines) * sizeof(bb_cell_t));
  493.         backbuf_clear(&vport->backbuf[BB_POS(vport, 0, vport->rows - lines)],
  494.             vport->cols * lines, vport->attr.fg_color, vport->attr.bg_color);
  495.     } else {
  496.         memmove(vport->backbuf - vport->cols * lines, vport->backbuf,
  497.             vport->cols * (vport->rows + lines) * sizeof(bb_cell_t));
  498.         backbuf_clear(vport->backbuf, - vport->cols * lines,
  499.             vport->attr.fg_color, vport->attr.bg_color);
  500.     }
  501. }
  502.  
  503. /** Render glyphs
  504.  *
  505.  * Convert glyphs from device independent font
  506.  * description to current visual representation.
  507.  *
  508.  */
  509. static void render_glyphs(void)
  510. {
  511.     unsigned int glyph;
  512.    
  513.     for (glyph = 0; glyph < FONT_GLYPHS; glyph++) {
  514.         unsigned int y;
  515.        
  516.         for (y = 0; y < FONT_SCANLINES; y++) {
  517.             unsigned int x;
  518.            
  519.             for (x = 0; x < FONT_WIDTH; x++) {
  520.                 screen.mask_conv(&screen.glyphs[GLYPH_POS(glyph, y, false) + x * screen.pixelbytes],
  521.                     (fb_font[glyph][y] & (1 << (7 - x))) ? true : false);
  522.                
  523.                 screen.mask_conv(&screen.glyphs[GLYPH_POS(glyph, y, true) + x * screen.pixelbytes],
  524.                     (fb_font[glyph][y] & (1 << (7 - x))) ? false : true);
  525.             }
  526.         }
  527.     }
  528. }
  529.  
  530. /** Create new viewport
  531.  *
  532.  * @param x      Origin of the viewport (x).
  533.  * @param y      Origin of the viewport (y).
  534.  * @param width  Width of the viewport.
  535.  * @param height Height of the viewport.
  536.  *
  537.  * @return New viewport number.
  538.  *
  539.  */
  540. static int vport_create(unsigned int x, unsigned int y,
  541.     unsigned int width, unsigned int height)
  542. {
  543.     unsigned int i;
  544.    
  545.     for (i = 0; i < MAX_VIEWPORTS; i++) {
  546.         if (!viewports[i].initialized)
  547.             break;
  548.     }
  549.    
  550.     if (i == MAX_VIEWPORTS)
  551.         return ELIMIT;
  552.    
  553.     unsigned int cols = width / FONT_WIDTH;
  554.     unsigned int rows = height / FONT_SCANLINES;
  555.     unsigned int bbsize = cols * rows * sizeof(bb_cell_t);
  556.     unsigned int word_size = sizeof(unsigned long);
  557.    
  558.     bb_cell_t *backbuf = (bb_cell_t *) malloc(bbsize);
  559.     if (!backbuf)
  560.         return ENOMEM;
  561.    
  562.     uint8_t *bgpixel = (uint8_t *) malloc(screen.pixelbytes);
  563.     if (!bgpixel) {
  564.         free(backbuf);
  565.         return ENOMEM;
  566.     }
  567.    
  568.     backbuf_clear(backbuf, cols * rows, DEFAULT_FGCOLOR, DEFAULT_BGCOLOR);
  569.     memset(bgpixel, 0, screen.pixelbytes);
  570.    
  571.     viewports[i].x = x;
  572.     viewports[i].y = y;
  573.     viewports[i].width = width;
  574.     viewports[i].height = height;
  575.    
  576.     viewports[i].cols = cols;
  577.     viewports[i].rows = rows;
  578.    
  579.     viewports[i].attr.bg_color = DEFAULT_BGCOLOR;
  580.     viewports[i].attr.fg_color = DEFAULT_FGCOLOR;
  581.    
  582.     viewports[i].bgpixel = bgpixel;
  583.    
  584.     /*
  585.      * Conditions necessary to select aligned version:
  586.      *  - word size is divisible by pixelbytes
  587.      *  - cell scanline size is divisible by word size
  588.      *  - cell scanlines are word-aligned
  589.      *
  590.      */
  591.     if (((word_size % screen.pixelbytes) == 0)
  592.         && ((FONT_WIDTH * screen.pixelbytes) % word_size == 0)
  593.         && ((x * screen.pixelbytes) % word_size == 0)
  594.         && (screen.scanline % word_size == 0)) {
  595.         viewports[i].dglyph = draw_glyph_aligned;
  596.     } else {
  597.         viewports[i].dglyph = draw_glyph_fallback;
  598.     }
  599.    
  600.     viewports[i].cur_col = 0;
  601.     viewports[i].cur_row = 0;
  602.     viewports[i].cursor_active = false;
  603.     viewports[i].cursor_shown = false;
  604.    
  605.     viewports[i].bbsize = bbsize;
  606.     viewports[i].backbuf = backbuf;
  607.    
  608.     viewports[i].initialized = true;
  609.    
  610.     screen.rgb_conv(viewports[i].bgpixel, viewports[i].attr.bg_color);
  611.    
  612.     return i;
  613. }
  614.  
  615.  
  616. /** Initialize framebuffer as a chardev output device
  617.  *
  618.  * @param addr   Address of the framebuffer
  619.  * @param xres   Screen width in pixels
  620.  * @param yres   Screen height in pixels
  621.  * @param visual Bits per pixel (8, 16, 24, 32)
  622.  * @param scan   Bytes per one scanline
  623.  *
  624.  */
  625. static bool screen_init(void *addr, unsigned int xres, unsigned int yres,
  626.     unsigned int scan, unsigned int visual)
  627. {
  628.     switch (visual) {
  629.     case VISUAL_INDIRECT_8:
  630.         screen.rgb_conv = bgr_323;
  631.         screen.mask_conv = mask_323;
  632.         screen.pixelbytes = 1;
  633.         break;
  634.     case VISUAL_RGB_5_5_5_LE:
  635.         screen.rgb_conv = rgb_555_le;
  636.         screen.mask_conv = mask_555;
  637.         screen.pixelbytes = 2;
  638.         break;
  639.     case VISUAL_RGB_5_5_5_BE:
  640.         screen.rgb_conv = rgb_555_be;
  641.         screen.mask_conv = mask_555;
  642.         screen.pixelbytes = 2;
  643.         break;
  644.     case VISUAL_RGB_5_6_5_LE:
  645.         screen.rgb_conv = rgb_565_le;
  646.         screen.mask_conv = mask_565;
  647.         screen.pixelbytes = 2;
  648.         break;
  649.     case VISUAL_RGB_5_6_5_BE:
  650.         screen.rgb_conv = rgb_565_be;
  651.         screen.mask_conv = mask_565;
  652.         screen.pixelbytes = 2;
  653.         break;
  654.     case VISUAL_RGB_8_8_8:
  655.         screen.rgb_conv = rgb_888;
  656.         screen.mask_conv = mask_888;
  657.         screen.pixelbytes = 3;
  658.         break;
  659.     case VISUAL_BGR_8_8_8:
  660.         screen.rgb_conv = bgr_888;
  661.         screen.mask_conv = mask_888;
  662.         screen.pixelbytes = 3;
  663.         break;
  664.     case VISUAL_RGB_8_8_8_0:
  665.         screen.rgb_conv = rgb_8880;
  666.         screen.mask_conv = mask_8880;
  667.         screen.pixelbytes = 4;
  668.         break;
  669.     case VISUAL_RGB_0_8_8_8:
  670.         screen.rgb_conv = rgb_0888;
  671.         screen.mask_conv = mask_0888;
  672.         screen.pixelbytes = 4;
  673.         break;
  674.     case VISUAL_BGR_0_8_8_8:
  675.         screen.rgb_conv = bgr_0888;
  676.         screen.mask_conv = mask_0888;
  677.         screen.pixelbytes = 4;
  678.         break;
  679.     case VISUAL_BGR_8_8_8_0:
  680.         screen.rgb_conv = bgr_8880;
  681.         screen.mask_conv = mask_8880;
  682.         screen.pixelbytes = 4;
  683.         break;
  684.     default:
  685.         return false;
  686.     }
  687.    
  688.     screen.fb_addr = (unsigned char *) addr;
  689.     screen.xres = xres;
  690.     screen.yres = yres;
  691.     screen.scanline = scan;
  692.    
  693.     screen.glyphscanline = FONT_WIDTH * screen.pixelbytes;
  694.     screen.glyphbytes = screen.glyphscanline * FONT_SCANLINES;
  695.    
  696.     size_t glyphsize = 2 * FONT_GLYPHS * screen.glyphbytes;
  697.     uint8_t *glyphs = (uint8_t *) malloc(glyphsize);
  698.     if (!glyphs)
  699.         return false;
  700.    
  701.     memset(glyphs, 0, glyphsize);
  702.     screen.glyphs = glyphs;
  703.    
  704.     render_glyphs();
  705.    
  706.     /* Create first viewport */
  707.     vport_create(0, 0, xres, yres);
  708.    
  709.     return true;
  710. }
  711.  
  712.  
  713. /** Draw a glyph, takes advantage of alignment.
  714.  *
  715.  * This version can only be used if the following conditions are met:
  716.  *
  717.  *   - word size is divisible by pixelbytes
  718.  *   - cell scanline size is divisible by word size
  719.  *   - cell scanlines are word-aligned
  720.  *
  721.  * It makes use of the pre-rendered mask to process (possibly) several
  722.  * pixels at once (word size / pixelbytes pixels at a time are processed)
  723.  * making it very fast. Most notably this version is not applicable at 24 bits
  724.  * per pixel.
  725.  *
  726.  * @param x        x coordinate of top-left corner on screen.
  727.  * @param y        y coordinate of top-left corner on screen.
  728.  * @param cursor   Draw glyph with cursor
  729.  * @param glyphs   Pointer to font bitmap.
  730.  * @param glyph    Code of the glyph to draw.
  731.  * @param fg_color Foreground color.
  732.  * @param bg_color Backgroudn color.
  733.  *
  734.  */
  735. static void draw_glyph_aligned(unsigned int x, unsigned int y, bool cursor,
  736.     uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color)
  737. {
  738.     unsigned int i;
  739.     unsigned int yd;
  740.     unsigned long fg_buf;
  741.     unsigned long bg_buf;
  742.     unsigned long mask;
  743.    
  744.     /*
  745.      * Prepare a pair of words, one filled with foreground-color
  746.      * pattern and the other filled with background-color pattern.
  747.      */
  748.     for (i = 0; i < sizeof(unsigned long) / screen.pixelbytes; i++) {
  749.         screen.rgb_conv(&((uint8_t *) &fg_buf)[i * screen.pixelbytes],
  750.             fg_color);
  751.         screen.rgb_conv(&((uint8_t *) &bg_buf)[i * screen.pixelbytes],
  752.             bg_color);
  753.     }
  754.    
  755.     /* Pointer to the current position in the mask. */
  756.     unsigned long *maskp = (unsigned long *) &glyphs[GLYPH_POS(glyph, 0, cursor)];
  757.    
  758.     /* Pointer to the current position on the screen. */
  759.     unsigned long *dp = (unsigned long *) &screen.fb_addr[FB_POS(x, y)];
  760.    
  761.     /* Width of the character cell in words. */
  762.     unsigned int ww = FONT_WIDTH * screen.pixelbytes / sizeof(unsigned long);
  763.    
  764.     /* Offset to add when moving to another screen scanline. */
  765.     unsigned int d_add = screen.scanline - FONT_WIDTH * screen.pixelbytes;
  766.    
  767.     for (yd = 0; yd < FONT_SCANLINES; yd++) {
  768.         /*
  769.          * Now process the cell scanline, combining foreground
  770.          * and background color patters using the pre-rendered mask.
  771.          */
  772.         for (i = 0; i < ww; i++) {
  773.             mask = *maskp++;
  774.             *dp++ = (fg_buf & mask) | (bg_buf & ~mask);
  775.         }
  776.        
  777.         /* Move to the beginning of the next scanline of the cell. */
  778.         dp = (unsigned long *) ((uint8_t *) dp + d_add);
  779.     }
  780. }
  781.  
  782. /** Draw a glyph, fallback version.
  783.  *
  784.  * This version does not make use of the pre-rendered mask, it uses
  785.  * the font bitmap directly. It works always, but it is slower.
  786.  *
  787.  * @param x        x coordinate of top-left corner on screen.
  788.  * @param y        y coordinate of top-left corner on screen.
  789.  * @param cursor   Draw glyph with cursor
  790.  * @param glyphs   Pointer to font bitmap.
  791.  * @param glyph    Code of the glyph to draw.
  792.  * @param fg_color Foreground color.
  793.  * @param bg_color Backgroudn color.
  794.  *
  795.  */
  796. void draw_glyph_fallback(unsigned int x, unsigned int y, bool cursor,
  797.     uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color)
  798. {
  799.     unsigned int i;
  800.     unsigned int j;
  801.     unsigned int yd;
  802.     uint8_t fg_buf[4];
  803.     uint8_t bg_buf[4];
  804.     uint8_t *sp;
  805.     uint8_t b;
  806.    
  807.     /* Pre-render 1x the foreground and background color pixels. */
  808.     if (cursor) {
  809.         screen.rgb_conv(fg_buf, bg_color);
  810.         screen.rgb_conv(bg_buf, fg_color);
  811.     } else {
  812.         screen.rgb_conv(fg_buf, fg_color);
  813.         screen.rgb_conv(bg_buf, bg_color);
  814.     }
  815.    
  816.     /* Pointer to the current position on the screen. */
  817.     uint8_t *dp = (uint8_t *) &screen.fb_addr[FB_POS(x, y)];
  818.    
  819.     /* Offset to add when moving to another screen scanline. */
  820.     unsigned int d_add = screen.scanline - FONT_WIDTH * screen.pixelbytes;
  821.    
  822.     for (yd = 0; yd < FONT_SCANLINES; yd++) {
  823.         /* Byte containing bits of the glyph scanline. */
  824.         b = fb_font[glyph][yd];
  825.        
  826.         for (i = 0; i < FONT_WIDTH; i++) {
  827.             /* Choose color based on the current bit. */
  828.             sp = (b & 0x80) ? fg_buf : bg_buf;
  829.            
  830.             /* Copy the pixel. */
  831.             for (j = 0; j < screen.pixelbytes; j++) {
  832.                 *dp++ = *sp++;
  833.             }
  834.            
  835.             /* Move to the next bit. */
  836.             b = b << 1;
  837.         }
  838.        
  839.         /* Move to the beginning of the next scanline of the cell. */
  840.         dp += d_add;
  841.     }
  842. }
  843.  
  844. /** Draw glyph at specified position in viewport.
  845.  *
  846.  * @param vport  Viewport identification
  847.  * @param cursor Draw glyph with cursor
  848.  * @param col    Screen position relative to viewport
  849.  * @param row    Screen position relative to viewport
  850.  *
  851.  */
  852. static void draw_vp_glyph(viewport_t *vport, bool cursor, unsigned int col,
  853.     unsigned int row)
  854. {
  855.     unsigned int x = vport->x + COL2X(col);
  856.     unsigned int y = vport->y + ROW2Y(row);
  857.    
  858.     uint32_t glyph = vport->backbuf[BB_POS(vport, col, row)].glyph;
  859.     uint32_t fg_color = vport->backbuf[BB_POS(vport, col, row)].fg_color;
  860.     uint32_t bg_color = vport->backbuf[BB_POS(vport, col, row)].bg_color;
  861.    
  862.     (*vport->dglyph)(x, y, cursor, screen.glyphs, glyph,
  863.         fg_color, bg_color);
  864. }
  865.  
  866. /** Hide cursor if it is shown
  867.  *
  868.  */
  869. static void cursor_hide(viewport_t *vport)
  870. {
  871.     if ((vport->cursor_active) && (vport->cursor_shown)) {
  872.         draw_vp_glyph(vport, false, vport->cur_col, vport->cur_row);
  873.         vport->cursor_shown = false;
  874.     }
  875. }
  876.  
  877.  
  878. /** Show cursor if cursor showing is enabled
  879.  *
  880.  */
  881. static void cursor_show(viewport_t *vport)
  882. {
  883.     /* Do not check for cursor_shown */
  884.     if (vport->cursor_active) {
  885.         draw_vp_glyph(vport, true, vport->cur_col, vport->cur_row);
  886.         vport->cursor_shown = true;
  887.     }
  888. }
  889.  
  890.  
  891. /** Invert cursor, if it is enabled
  892.  *
  893.  */
  894. static void cursor_blink(viewport_t *vport)
  895. {
  896.     if (vport->cursor_shown)
  897.         cursor_hide(vport);
  898.     else
  899.         cursor_show(vport);
  900. }
  901.  
  902.  
  903. /** Draw character at given position relative to viewport
  904.  *
  905.  * @param vport  Viewport identification
  906.  * @param c      Character to draw
  907.  * @param col    Screen position relative to viewport
  908.  * @param row    Screen position relative to viewport
  909.  *
  910.  */
  911. static void draw_char(viewport_t *vport, wchar_t c, unsigned int col, unsigned int row)
  912. {
  913.     bb_cell_t *bbp;
  914.    
  915.     /* Do not hide cursor if we are going to overwrite it */
  916.     if ((vport->cursor_active) && (vport->cursor_shown) &&
  917.         ((vport->cur_col != col) || (vport->cur_row != row)))
  918.         cursor_hide(vport);
  919.    
  920.     bbp = &vport->backbuf[BB_POS(vport, col, row)];
  921.     bbp->glyph = fb_font_glyph(c);
  922.     bbp->fg_color = vport->attr.fg_color;
  923.     bbp->bg_color = vport->attr.bg_color;
  924.    
  925.     draw_vp_glyph(vport, false, col, row);
  926.    
  927.     vport->cur_col = col;
  928.     vport->cur_row = row;
  929.    
  930.     vport->cur_col++;
  931.     if (vport->cur_col >= vport->cols) {
  932.         vport->cur_col = 0;
  933.         vport->cur_row++;
  934.         if (vport->cur_row >= vport->rows)
  935.             vport->cur_row--;
  936.     }
  937.    
  938.     cursor_show(vport);
  939. }
  940.  
  941. /** Draw text data to viewport.
  942.  *
  943.  * @param vport Viewport id
  944.  * @param data  Text data.
  945.  * @param x     Leftmost column of the area.
  946.  * @param y     Topmost row of the area.
  947.  * @param w     Number of rows.
  948.  * @param h     Number of columns.
  949.  *
  950.  */
  951. static void draw_text_data(viewport_t *vport, keyfield_t *data, unsigned int x,
  952.     unsigned int y, unsigned int w, unsigned int h)
  953. {
  954.     unsigned int i;
  955.     unsigned int j;
  956.     bb_cell_t *bbp;
  957.     attrs_t *a;
  958.     attr_rgb_t rgb;
  959.    
  960.     for (j = 0; j < h; j++) {
  961.         for (i = 0; i < w; i++) {
  962.             unsigned int col = x + i;
  963.             unsigned int row = y + j;
  964.            
  965.             bbp = &vport->backbuf[BB_POS(vport, col, row)];
  966.            
  967.             a = &data[j * w + i].attrs;
  968.             rgb_from_attr(&rgb, a);
  969.            
  970.             bbp->glyph = fb_font_glyph(data[j * w + i].character);
  971.             bbp->fg_color = rgb.fg_color;
  972.             bbp->bg_color = rgb.bg_color;
  973.            
  974.             draw_vp_glyph(vport, false, col, row);
  975.         }
  976.     }
  977.     cursor_show(vport);
  978. }
  979.  
  980.  
  981. static void putpixel_pixmap(void *data, unsigned int x, unsigned int y, uint32_t color)
  982. {
  983.     int pm = *((int *) data);
  984.     pixmap_t *pmap = &pixmaps[pm];
  985.     unsigned int pos = (y * pmap->width + x) * screen.pixelbytes;
  986.    
  987.     screen.rgb_conv(&pmap->data[pos], color);
  988. }
  989.  
  990.  
  991. static void putpixel(void *data, unsigned int x, unsigned int y, uint32_t color)
  992. {
  993.     viewport_t *vport = (viewport_t *) data;
  994.     unsigned int dx = vport->x + x;
  995.     unsigned int dy = vport->y + y;
  996.    
  997.     screen.rgb_conv(&screen.fb_addr[FB_POS(dx, dy)], color);
  998. }
  999.  
  1000.  
  1001. /** Return first free pixmap
  1002.  *
  1003.  */
  1004. static int find_free_pixmap(void)
  1005. {
  1006.     unsigned int i;
  1007.    
  1008.     for (i = 0; i < MAX_PIXMAPS; i++)
  1009.         if (!pixmaps[i].data)
  1010.             return i;
  1011.    
  1012.     return -1;
  1013. }
  1014.  
  1015.  
  1016. /** Create a new pixmap and return appropriate ID
  1017.  *
  1018.  */
  1019. static int shm2pixmap(unsigned char *shm, size_t size)
  1020. {
  1021.     int pm;
  1022.     pixmap_t *pmap;
  1023.    
  1024.     pm = find_free_pixmap();
  1025.     if (pm == -1)
  1026.         return ELIMIT;
  1027.    
  1028.     pmap = &pixmaps[pm];
  1029.    
  1030.     if (ppm_get_data(shm, size, &pmap->width, &pmap->height))
  1031.         return EINVAL;
  1032.    
  1033.     pmap->data = malloc(pmap->width * pmap->height * screen.pixelbytes);
  1034.     if (!pmap->data)
  1035.         return ENOMEM;
  1036.    
  1037.     ppm_draw(shm, size, 0, 0, pmap->width, pmap->height, putpixel_pixmap, (void *) &pm);
  1038.    
  1039.     return pm;
  1040. }
  1041.  
  1042.  
  1043. /** Handle shared memory communication calls
  1044.  *
  1045.  * Protocol for drawing pixmaps:
  1046.  * - FB_PREPARE_SHM(client shm identification)
  1047.  * - IPC_M_AS_AREA_SEND
  1048.  * - FB_DRAW_PPM(startx, starty)
  1049.  * - FB_DROP_SHM
  1050.  *
  1051.  * Protocol for text drawing
  1052.  * - IPC_M_AS_AREA_SEND
  1053.  * - FB_DRAW_TEXT_DATA
  1054.  *
  1055.  * @param callid Callid of the current call
  1056.  * @param call   Current call data
  1057.  * @param vp     Active viewport
  1058.  *
  1059.  * @return false if the call was not handled byt this function, true otherwise
  1060.  *
  1061.  * Note: this function is not thread-safe, you would have
  1062.  * to redefine static variables with fibril_local.
  1063.  *
  1064.  */
  1065. static bool shm_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
  1066. {
  1067.     static keyfield_t *interbuffer = NULL;
  1068.     static size_t intersize = 0;
  1069.    
  1070.     static unsigned char *shm = NULL;
  1071.     static ipcarg_t shm_id = 0;
  1072.     static size_t shm_size;
  1073.    
  1074.     bool handled = true;
  1075.     int retval = EOK;
  1076.     viewport_t *vport = &viewports[vp];
  1077.     unsigned int x;
  1078.     unsigned int y;
  1079.     unsigned int w;
  1080.     unsigned int h;
  1081.    
  1082.     switch (IPC_GET_METHOD(*call)) {
  1083.     case IPC_M_SHARE_OUT:
  1084.         /* We accept one area for data interchange */
  1085.         if (IPC_GET_ARG1(*call) == shm_id) {
  1086.             void *dest = as_get_mappable_page(IPC_GET_ARG2(*call));
  1087.             shm_size = IPC_GET_ARG2(*call);
  1088.             if (ipc_answer_1(callid, EOK, (sysarg_t) dest)) {
  1089.                 shm_id = 0;
  1090.                 return false;
  1091.             }
  1092.             shm = dest;
  1093.            
  1094.             if (shm[0] != 'P')
  1095.                 return false;
  1096.            
  1097.             return true;
  1098.         } else {
  1099.             intersize = IPC_GET_ARG2(*call);
  1100.             receive_comm_area(callid, call, (void *) &interbuffer);
  1101.         }
  1102.         return true;
  1103.     case FB_PREPARE_SHM:
  1104.         if (shm_id)
  1105.             retval = EBUSY;
  1106.         else
  1107.             shm_id = IPC_GET_ARG1(*call);
  1108.         break;
  1109.        
  1110.     case FB_DROP_SHM:
  1111.         if (shm) {
  1112.             as_area_destroy(shm);
  1113.             shm = NULL;
  1114.         }
  1115.         shm_id = 0;
  1116.         break;
  1117.        
  1118.     case FB_SHM2PIXMAP:
  1119.         if (!shm) {
  1120.             retval = EINVAL;
  1121.             break;
  1122.         }
  1123.         retval = shm2pixmap(shm, shm_size);
  1124.         break;
  1125.     case FB_DRAW_PPM:
  1126.         if (!shm) {
  1127.             retval = EINVAL;
  1128.             break;
  1129.         }
  1130.         x = IPC_GET_ARG1(*call);
  1131.         y = IPC_GET_ARG2(*call);
  1132.        
  1133.         if ((x > vport->width) || (y > vport->height)) {
  1134.             retval = EINVAL;
  1135.             break;
  1136.         }
  1137.        
  1138.         ppm_draw(shm, shm_size, IPC_GET_ARG1(*call),
  1139.             IPC_GET_ARG2(*call), vport->width - x, vport->height - y, putpixel, (void *) vport);
  1140.         break;
  1141.     case FB_DRAW_TEXT_DATA:
  1142.         x = IPC_GET_ARG1(*call);
  1143.         y = IPC_GET_ARG2(*call);
  1144.         w = IPC_GET_ARG3(*call);
  1145.         h = IPC_GET_ARG4(*call);
  1146.         if (!interbuffer) {
  1147.             retval = EINVAL;
  1148.             break;
  1149.         }
  1150.         if (x + w > vport->cols || y + h > vport->rows) {
  1151.             retval = EINVAL;
  1152.             break;
  1153.         }
  1154.         if (intersize < w * h * sizeof(*interbuffer)) {
  1155.             retval = EINVAL;
  1156.             break;
  1157.         }
  1158.         draw_text_data(vport, interbuffer, x, y, w, h);
  1159.         break;
  1160.     default:
  1161.         handled = false;
  1162.     }
  1163.    
  1164.     if (handled)
  1165.         ipc_answer_0(callid, retval);
  1166.     return handled;
  1167. }
  1168.  
  1169.  
  1170. static void copy_vp_to_pixmap(viewport_t *vport, pixmap_t *pmap)
  1171. {
  1172.     unsigned int width = vport->width;
  1173.     unsigned int height = vport->height;
  1174.    
  1175.     if (width + vport->x > screen.xres)
  1176.         width = screen.xres - vport->x;
  1177.     if (height + vport->y > screen.yres)
  1178.         height = screen.yres - vport->y;
  1179.    
  1180.     unsigned int realwidth = pmap->width <= width ? pmap->width : width;
  1181.     unsigned int realheight = pmap->height <= height ? pmap->height : height;
  1182.    
  1183.     unsigned int srcrowsize = vport->width * screen.pixelbytes;
  1184.     unsigned int realrowsize = realwidth * screen.pixelbytes;
  1185.    
  1186.     unsigned int y;
  1187.     for (y = 0; y < realheight; y++) {
  1188.         unsigned int tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;
  1189.         memcpy(pmap->data + srcrowsize * y, screen.fb_addr + tmp, realrowsize);
  1190.     }
  1191. }
  1192.  
  1193.  
  1194. /** Save viewport to pixmap
  1195.  *
  1196.  */
  1197. static int save_vp_to_pixmap(viewport_t *vport)
  1198. {
  1199.     int pm;
  1200.     pixmap_t *pmap;
  1201.    
  1202.     pm = find_free_pixmap();
  1203.     if (pm == -1)
  1204.         return ELIMIT;
  1205.    
  1206.     pmap = &pixmaps[pm];
  1207.     pmap->data = malloc(screen.pixelbytes * vport->width * vport->height);
  1208.     if (!pmap->data)
  1209.         return ENOMEM;
  1210.    
  1211.     pmap->width = vport->width;
  1212.     pmap->height = vport->height;
  1213.    
  1214.     copy_vp_to_pixmap(vport, pmap);
  1215.    
  1216.     return pm;
  1217. }
  1218.  
  1219.  
  1220. /** Draw pixmap on screen
  1221.  *
  1222.  * @param vp Viewport to draw on
  1223.  * @param pm Pixmap identifier
  1224.  *
  1225.  */
  1226. static int draw_pixmap(int vp, int pm)
  1227. {
  1228.     pixmap_t *pmap = &pixmaps[pm];
  1229.     viewport_t *vport = &viewports[vp];
  1230.    
  1231.     unsigned int width = vport->width;
  1232.     unsigned int height = vport->height;
  1233.    
  1234.     if (width + vport->x > screen.xres)
  1235.         width = screen.xres - vport->x;
  1236.     if (height + vport->y > screen.yres)
  1237.         height = screen.yres - vport->y;
  1238.    
  1239.     if (!pmap->data)
  1240.         return EINVAL;
  1241.    
  1242.     unsigned int realwidth = pmap->width <= width ? pmap->width : width;
  1243.     unsigned int realheight = pmap->height <= height ? pmap->height : height;
  1244.    
  1245.     unsigned int srcrowsize = vport->width * screen.pixelbytes;
  1246.     unsigned int realrowsize = realwidth * screen.pixelbytes;
  1247.    
  1248.     unsigned int y;
  1249.     for (y = 0; y < realheight; y++) {
  1250.         unsigned int tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;
  1251.         memcpy(screen.fb_addr + tmp, pmap->data + y * srcrowsize, realrowsize);
  1252.     }
  1253.    
  1254.     return EOK;
  1255. }
  1256.  
  1257.  
  1258. /** Tick animation one step forward
  1259.  *
  1260.  */
  1261. static void anims_tick(void)
  1262. {
  1263.     unsigned int i;
  1264.     static int counts = 0;
  1265.    
  1266.     /* Limit redrawing */
  1267.     counts = (counts + 1) % 8;
  1268.     if (counts)
  1269.         return;
  1270.    
  1271.     for (i = 0; i < MAX_ANIMATIONS; i++) {
  1272.         if ((!animations[i].animlen) || (!animations[i].initialized) ||
  1273.             (!animations[i].enabled))
  1274.             continue;
  1275.        
  1276.         draw_pixmap(animations[i].vp, animations[i].pixmaps[animations[i].pos]);
  1277.         animations[i].pos = (animations[i].pos + 1) % animations[i].animlen;
  1278.     }
  1279. }
  1280.  
  1281.  
  1282. static unsigned int pointer_x;
  1283. static unsigned int pointer_y;
  1284. static bool pointer_shown, pointer_enabled;
  1285. static int pointer_vport = -1;
  1286. static int pointer_pixmap = -1;
  1287.  
  1288.  
  1289. static void mouse_show(void)
  1290. {
  1291.     int i, j;
  1292.     int visibility;
  1293.     int color;
  1294.     int bytepos;
  1295.    
  1296.     if ((pointer_shown) || (!pointer_enabled))
  1297.         return;
  1298.    
  1299.     /* Save image under the pointer. */
  1300.     if (pointer_vport == -1) {
  1301.         pointer_vport = vport_create(pointer_x, pointer_y, pointer_width, pointer_height);
  1302.         if (pointer_vport < 0)
  1303.             return;
  1304.     } else {
  1305.         viewports[pointer_vport].x = pointer_x;
  1306.         viewports[pointer_vport].y = pointer_y;
  1307.     }
  1308.    
  1309.     if (pointer_pixmap == -1)
  1310.         pointer_pixmap = save_vp_to_pixmap(&viewports[pointer_vport]);
  1311.     else
  1312.         copy_vp_to_pixmap(&viewports[pointer_vport], &pixmaps[pointer_pixmap]);
  1313.    
  1314.     /* Draw mouse pointer. */
  1315.     for (i = 0; i < pointer_height; i++)
  1316.         for (j = 0; j < pointer_width; j++) {
  1317.             bytepos = i * ((pointer_width - 1) / 8 + 1) + j / 8;
  1318.             visibility = pointer_mask_bits[bytepos] &
  1319.                 (1 << (j % 8));
  1320.             if (visibility) {
  1321.                 color = pointer_bits[bytepos] &
  1322.                     (1 << (j % 8)) ? 0 : 0xffffff;
  1323.                 if (pointer_x + j < screen.xres && pointer_y +
  1324.                     i < screen.yres)
  1325.                     putpixel(&viewports[0], pointer_x + j,
  1326.                         pointer_y + i, color);
  1327.             }
  1328.         }
  1329.     pointer_shown = 1;
  1330. }
  1331.  
  1332.  
  1333. static void mouse_hide(void)
  1334. {
  1335.     /* Restore image under the pointer. */
  1336.     if (pointer_shown) {
  1337.         draw_pixmap(pointer_vport, pointer_pixmap);
  1338.         pointer_shown = 0;
  1339.     }
  1340. }
  1341.  
  1342.  
  1343. static void mouse_move(unsigned int x, unsigned int y)
  1344. {
  1345.     mouse_hide();
  1346.     pointer_x = x;
  1347.     pointer_y = y;
  1348.     mouse_show();
  1349. }
  1350.  
  1351.  
  1352. static int anim_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
  1353. {
  1354.     bool handled = true;
  1355.     int retval = EOK;
  1356.     int i, nvp;
  1357.     int newval;
  1358.    
  1359.     switch (IPC_GET_METHOD(*call)) {
  1360.     case FB_ANIM_CREATE:
  1361.         nvp = IPC_GET_ARG1(*call);
  1362.         if (nvp == -1)
  1363.             nvp = vp;
  1364.         if (nvp >= MAX_VIEWPORTS || nvp < 0 ||
  1365.             !viewports[nvp].initialized) {
  1366.             retval = EINVAL;
  1367.             break;
  1368.         }
  1369.         for (i = 0; i < MAX_ANIMATIONS; i++) {
  1370.             if (!animations[i].initialized)
  1371.                 break;
  1372.         }
  1373.         if (i == MAX_ANIMATIONS) {
  1374.             retval = ELIMIT;
  1375.             break;
  1376.         }
  1377.         animations[i].initialized = 1;
  1378.         animations[i].animlen = 0;
  1379.         animations[i].pos = 0;
  1380.         animations[i].enabled = 0;
  1381.         animations[i].vp = nvp;
  1382.         retval = i;
  1383.         break;
  1384.     case FB_ANIM_DROP:
  1385.         i = IPC_GET_ARG1(*call);
  1386.         if (i >= MAX_ANIMATIONS || i < 0) {
  1387.             retval = EINVAL;
  1388.             break;
  1389.         }
  1390.         animations[i].initialized = 0;
  1391.         break;
  1392.     case FB_ANIM_ADDPIXMAP:
  1393.         i = IPC_GET_ARG1(*call);
  1394.         if (i >= MAX_ANIMATIONS || i < 0 ||
  1395.             !animations[i].initialized) {
  1396.             retval = EINVAL;
  1397.             break;
  1398.         }
  1399.         if (animations[i].animlen == MAX_ANIM_LEN) {
  1400.             retval = ELIMIT;
  1401.             break;
  1402.         }
  1403.         newval = IPC_GET_ARG2(*call);
  1404.         if (newval < 0 || newval > MAX_PIXMAPS ||
  1405.             !pixmaps[newval].data) {
  1406.             retval = EINVAL;
  1407.             break;
  1408.         }
  1409.         animations[i].pixmaps[animations[i].animlen++] = newval;
  1410.         break;
  1411.     case FB_ANIM_CHGVP:
  1412.         i = IPC_GET_ARG1(*call);
  1413.         if (i >= MAX_ANIMATIONS || i < 0) {
  1414.             retval = EINVAL;
  1415.             break;
  1416.         }
  1417.         nvp = IPC_GET_ARG2(*call);
  1418.         if (nvp == -1)
  1419.             nvp = vp;
  1420.         if (nvp >= MAX_VIEWPORTS || nvp < 0 ||
  1421.             !viewports[nvp].initialized) {
  1422.             retval = EINVAL;
  1423.             break;
  1424.         }
  1425.         animations[i].vp = nvp;
  1426.         break;
  1427.     case FB_ANIM_START:
  1428.     case FB_ANIM_STOP:
  1429.         i = IPC_GET_ARG1(*call);
  1430.         if (i >= MAX_ANIMATIONS || i < 0) {
  1431.             retval = EINVAL;
  1432.             break;
  1433.         }
  1434.         newval = (IPC_GET_METHOD(*call) == FB_ANIM_START);
  1435.         if (newval ^ animations[i].enabled) {
  1436.             animations[i].enabled = newval;
  1437.             anims_enabled += newval ? 1 : -1;
  1438.         }
  1439.         break;
  1440.     default:
  1441.         handled = 0;
  1442.     }
  1443.     if (handled)
  1444.         ipc_answer_0(callid, retval);
  1445.     return handled;
  1446. }
  1447.  
  1448.  
  1449. /** Handler for messages concerning pixmap handling
  1450.  *
  1451.  */
  1452. static int pixmap_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
  1453. {
  1454.     bool handled = true;
  1455.     int retval = EOK;
  1456.     int i, nvp;
  1457.    
  1458.     switch (IPC_GET_METHOD(*call)) {
  1459.     case FB_VP_DRAW_PIXMAP:
  1460.         nvp = IPC_GET_ARG1(*call);
  1461.         if (nvp == -1)
  1462.             nvp = vp;
  1463.         if (nvp < 0 || nvp >= MAX_VIEWPORTS ||
  1464.             !viewports[nvp].initialized) {
  1465.             retval = EINVAL;
  1466.             break;
  1467.         }
  1468.         i = IPC_GET_ARG2(*call);
  1469.         retval = draw_pixmap(nvp, i);
  1470.         break;
  1471.     case FB_VP2PIXMAP:
  1472.         nvp = IPC_GET_ARG1(*call);
  1473.         if (nvp == -1)
  1474.             nvp = vp;
  1475.         if (nvp < 0 || nvp >= MAX_VIEWPORTS ||
  1476.             !viewports[nvp].initialized)
  1477.             retval = EINVAL;
  1478.         else
  1479.             retval = save_vp_to_pixmap(&viewports[nvp]);
  1480.         break;
  1481.     case FB_DROP_PIXMAP:
  1482.         i = IPC_GET_ARG1(*call);
  1483.         if (i >= MAX_PIXMAPS) {
  1484.             retval = EINVAL;
  1485.             break;
  1486.         }
  1487.         if (pixmaps[i].data) {
  1488.             free(pixmaps[i].data);
  1489.             pixmaps[i].data = NULL;
  1490.         }
  1491.         break;
  1492.     default:
  1493.         handled = 0;
  1494.     }
  1495.    
  1496.     if (handled)
  1497.         ipc_answer_0(callid, retval);
  1498.     return handled;
  1499.    
  1500. }
  1501.  
  1502. static int rgb_from_style(attr_rgb_t *rgb, int style)
  1503. {
  1504.     switch (style) {
  1505.     case STYLE_NORMAL:
  1506.         rgb->fg_color = color_table[COLOR_BLACK];
  1507.         rgb->bg_color = color_table[COLOR_WHITE];
  1508.         break;
  1509.     case STYLE_EMPHASIS:
  1510.         rgb->fg_color = color_table[COLOR_RED];
  1511.         rgb->bg_color = color_table[COLOR_WHITE];
  1512.         break;
  1513.     default:
  1514.         return EINVAL;
  1515.     }
  1516.  
  1517.     return EOK;
  1518. }
  1519.  
  1520. static int rgb_from_idx(attr_rgb_t *rgb, ipcarg_t fg_color,
  1521.     ipcarg_t bg_color, ipcarg_t flags)
  1522. {
  1523.     fg_color = (fg_color & 7) | ((flags & CATTR_BRIGHT) ? 8 : 0);
  1524.     bg_color = (bg_color & 7) | ((flags & CATTR_BRIGHT) ? 8 : 0);
  1525.  
  1526.     rgb->fg_color = color_table[fg_color];
  1527.     rgb->bg_color = color_table[bg_color];
  1528.  
  1529.     return EOK;
  1530. }
  1531.  
  1532. static int rgb_from_attr(attr_rgb_t *rgb, const attrs_t *a)
  1533. {
  1534.     int rc;
  1535.  
  1536.     switch (a->t) {
  1537.     case at_style:
  1538.         rc = rgb_from_style(rgb, a->a.s.style);
  1539.         break;
  1540.     case at_idx:
  1541.         rc = rgb_from_idx(rgb, a->a.i.fg_color,
  1542.             a->a.i.bg_color, a->a.i.flags);
  1543.         break;
  1544.     case at_rgb:
  1545.         *rgb = a->a.r;
  1546.         rc = EOK;
  1547.         break;
  1548.     }
  1549.  
  1550.     return rc;
  1551. }
  1552.  
  1553. static int fb_set_style(viewport_t *vport, ipcarg_t style)
  1554. {
  1555.     return rgb_from_style(&vport->attr, (int) style);
  1556. }
  1557.  
  1558. static int fb_set_color(viewport_t *vport, ipcarg_t fg_color,
  1559.     ipcarg_t bg_color, ipcarg_t flags)
  1560. {
  1561.     return rgb_from_idx(&vport->attr, fg_color, bg_color, flags);
  1562. }
  1563.  
  1564. /** Function for handling connections to FB
  1565.  *
  1566.  */
  1567. static void fb_client_connection(ipc_callid_t iid, ipc_call_t *icall)
  1568. {
  1569.     unsigned int vp = 0;
  1570.     viewport_t *vport = &viewports[vp];
  1571.    
  1572.     if (client_connected) {
  1573.         ipc_answer_0(iid, ELIMIT);
  1574.         return;
  1575.     }
  1576.    
  1577.     /* Accept connection */
  1578.     client_connected = true;
  1579.     ipc_answer_0(iid, EOK);
  1580.    
  1581.     while (true) {
  1582.         ipc_callid_t callid;
  1583.         ipc_call_t call;
  1584.         int retval;
  1585.         unsigned int i;
  1586.         int scroll;
  1587.         wchar_t ch;
  1588.         unsigned int col, row;
  1589.        
  1590.         if ((vport->cursor_active) || (anims_enabled))
  1591.             callid = async_get_call_timeout(&call, 250000);
  1592.         else
  1593.             callid = async_get_call(&call);
  1594.        
  1595.         mouse_hide();
  1596.         if (!callid) {
  1597.             cursor_blink(vport);
  1598.             anims_tick();
  1599.             mouse_show();
  1600.             continue;
  1601.         }
  1602.        
  1603.         if (shm_handle(callid, &call, vp))
  1604.             continue;
  1605.        
  1606.         if (pixmap_handle(callid, &call, vp))
  1607.             continue;
  1608.        
  1609.         if (anim_handle(callid, &call, vp))
  1610.             continue;
  1611.        
  1612.         switch (IPC_GET_METHOD(call)) {
  1613.         case IPC_M_PHONE_HUNGUP:
  1614.             client_connected = false;
  1615.            
  1616.             /* Cleanup other viewports */
  1617.             for (i = 1; i < MAX_VIEWPORTS; i++)
  1618.                 vport->initialized = false;
  1619.            
  1620.             /* Exit thread */
  1621.             return;
  1622.        
  1623.         case FB_PUTCHAR:
  1624.             ch = IPC_GET_ARG1(call);
  1625.             col = IPC_GET_ARG2(call);
  1626.             row = IPC_GET_ARG3(call);
  1627.            
  1628.             if ((col >= vport->cols) || (row >= vport->rows)) {
  1629.                 retval = EINVAL;
  1630.                 break;
  1631.             }
  1632.             ipc_answer_0(callid, EOK);
  1633.            
  1634.             draw_char(vport, ch, col, row);
  1635.            
  1636.             /* Message already answered */
  1637.             continue;
  1638.         case FB_CLEAR:
  1639.             vport_clear(vport);
  1640.             cursor_show(vport);
  1641.             retval = EOK;
  1642.             break;
  1643.         case FB_CURSOR_GOTO:
  1644.             col = IPC_GET_ARG1(call);
  1645.             row = IPC_GET_ARG2(call);
  1646.            
  1647.             if ((col >= vport->cols) || (row >= vport->rows)) {
  1648.                 retval = EINVAL;
  1649.                 break;
  1650.             }
  1651.             retval = EOK;
  1652.            
  1653.             cursor_hide(vport);
  1654.             vport->cur_col = col;
  1655.             vport->cur_row = row;
  1656.             cursor_show(vport);
  1657.             break;
  1658.         case FB_CURSOR_VISIBILITY:
  1659.             cursor_hide(vport);
  1660.             vport->cursor_active = IPC_GET_ARG1(call);
  1661.             cursor_show(vport);
  1662.             retval = EOK;
  1663.             break;
  1664.         case FB_GET_CSIZE:
  1665.             ipc_answer_2(callid, EOK, vport->cols, vport->rows);
  1666.             continue;
  1667.         case FB_GET_COLOR_CAP:
  1668.             ipc_answer_1(callid, EOK, FB_CCAP_RGB);
  1669.             continue;
  1670.         case FB_SCROLL:
  1671.             scroll = IPC_GET_ARG1(call);
  1672.             if ((scroll > (int) vport->rows) || (scroll < (-(int) vport->rows))) {
  1673.                 retval = EINVAL;
  1674.                 break;
  1675.             }
  1676.             cursor_hide(vport);
  1677.             vport_scroll(vport, scroll);
  1678.             cursor_show(vport);
  1679.             retval = EOK;
  1680.             break;
  1681.         case FB_VIEWPORT_SWITCH:
  1682.             i = IPC_GET_ARG1(call);
  1683.             if (i >= MAX_VIEWPORTS) {
  1684.                 retval = EINVAL;
  1685.                 break;
  1686.             }
  1687.             if (!viewports[i].initialized) {
  1688.                 retval = EADDRNOTAVAIL;
  1689.                 break;
  1690.             }
  1691.             cursor_hide(vport);
  1692.             vp = i;
  1693.             vport = &viewports[vp];
  1694.             cursor_show(vport);
  1695.             retval = EOK;
  1696.             break;
  1697.         case FB_VIEWPORT_CREATE:
  1698.             retval = vport_create(IPC_GET_ARG1(call) >> 16,
  1699.                 IPC_GET_ARG1(call) & 0xffff,
  1700.                 IPC_GET_ARG2(call) >> 16,
  1701.                 IPC_GET_ARG2(call) & 0xffff);
  1702.             break;
  1703.         case FB_VIEWPORT_DELETE:
  1704.             i = IPC_GET_ARG1(call);
  1705.             if (i >= MAX_VIEWPORTS) {
  1706.                 retval = EINVAL;
  1707.                 break;
  1708.             }
  1709.             if (!viewports[i].initialized) {
  1710.                 retval = EADDRNOTAVAIL;
  1711.                 break;
  1712.             }
  1713.             viewports[i].initialized = false;
  1714.             if (viewports[i].bgpixel)
  1715.                 free(viewports[i].bgpixel);
  1716.             if (viewports[i].backbuf)
  1717.                 free(viewports[i].backbuf);
  1718.             retval = EOK;
  1719.             break;
  1720.         case FB_SET_STYLE:
  1721.             retval = fb_set_style(vport, IPC_GET_ARG1(call));
  1722.             break;
  1723.         case FB_SET_COLOR:
  1724.             retval = fb_set_color(vport, IPC_GET_ARG1(call),
  1725.                 IPC_GET_ARG2(call), IPC_GET_ARG3(call));
  1726.             break;
  1727.         case FB_SET_RGB_COLOR:
  1728.             vport->attr.fg_color = IPC_GET_ARG1(call);
  1729.             vport->attr.bg_color = IPC_GET_ARG2(call);
  1730.             retval = EOK;
  1731.             break;
  1732.         case FB_GET_RESOLUTION:
  1733.             ipc_answer_2(callid, EOK, screen.xres, screen.yres);
  1734.             continue;
  1735.         case FB_POINTER_MOVE:
  1736.             pointer_enabled = true;
  1737.             mouse_move(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
  1738.             retval = EOK;
  1739.             break;
  1740.         case FB_SCREEN_YIELD:
  1741.         case FB_SCREEN_RECLAIM:
  1742.             retval = EOK;
  1743.             break;
  1744.         default:
  1745.             retval = ENOENT;
  1746.         }
  1747.         ipc_answer_0(callid, retval);
  1748.     }
  1749. }
  1750.  
  1751. /** Initialization of framebuffer
  1752.  *
  1753.  */
  1754. int fb_init(void)
  1755. {
  1756.     async_set_client_connection(fb_client_connection);
  1757.    
  1758.     void *fb_ph_addr = (void *) sysinfo_value("fb.address.physical");
  1759.     unsigned int fb_offset = sysinfo_value("fb.offset");
  1760.     unsigned int fb_width = sysinfo_value("fb.width");
  1761.     unsigned int fb_height = sysinfo_value("fb.height");
  1762.     unsigned int fb_scanline = sysinfo_value("fb.scanline");
  1763.     unsigned int fb_visual = sysinfo_value("fb.visual");
  1764.  
  1765.     unsigned int fbsize = fb_scanline * fb_height;
  1766.     void *fb_addr = as_get_mappable_page(fbsize);
  1767.  
  1768.     if (physmem_map(fb_ph_addr + fb_offset, fb_addr,
  1769.         ALIGN_UP(fbsize, PAGE_SIZE) >> PAGE_WIDTH, AS_AREA_READ | AS_AREA_WRITE) != 0)
  1770.         return -1;
  1771.  
  1772.     if (screen_init(fb_addr, fb_width, fb_height, fb_scanline, fb_visual))
  1773.         return 0;
  1774.  
  1775.     return -1;
  1776. }
  1777.  
  1778. /**
  1779.  * @}
  1780.  */
  1781.