static void vga_draw_text(VGAState *s, int full_update)

{

    int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;

    int cx_min, cx_max, linesize, x_incr;

    uint32_t offset, fgcol, bgcol, v, cursor_offset;

    uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;

    const uint8_t *font_ptr, *font_base[2];

    int dup9, line_offset, depth_index;

    uint32_t *palette;

    uint32_t *ch_attr_ptr;

    vga_draw_glyph8_func *vga_draw_glyph8;

    vga_draw_glyph9_func *vga_draw_glyph9;



    vga_dirty_log_stop(s);



    /* compute font data address (in plane 2) */

    v = s->sr[3];

    offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;

    if (offset != s->font_offsets[0]) {

        s->font_offsets[0] = offset;

        full_update = 1;

    }

    font_base[0] = s->vram_ptr + offset;



    offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;

    font_base[1] = s->vram_ptr + offset;

    if (offset != s->font_offsets[1]) {

        s->font_offsets[1] = offset;

        full_update = 1;

    }

    if (s->plane_updated & (1 << 2)) {

        /* if the plane 2 was modified since the last display, it

           indicates the font may have been modified */

        s->plane_updated = 0;

        full_update = 1;

    }

    full_update |= update_basic_params(s);



    line_offset = s->line_offset;

    s1 = s->vram_ptr + (s->start_addr * 4);



    vga_get_text_resolution(s, &width, &height, &cw, &cheight);

    x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);

    if ((height * width) > CH_ATTR_SIZE) {

        /* better than nothing: exit if transient size is too big */

        return;

    }



    if (width != s->last_width || height != s->last_height ||

        cw != s->last_cw || cheight != s->last_ch || s->last_depth) {

        s->last_scr_width = width * cw;

        s->last_scr_height = height * cheight;

        qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height);

        s->last_depth = 0;

        s->last_width = width;

        s->last_height = height;

        s->last_ch = cheight;

        s->last_cw = cw;

        full_update = 1;

    }

    s->rgb_to_pixel =

        rgb_to_pixel_dup_table[get_depth_index(s->ds)];

    full_update |= update_palette16(s);

    palette = s->last_palette;

    x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);



    cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;

    if (cursor_offset != s->cursor_offset ||

        s->cr[0xa] != s->cursor_start ||

        s->cr[0xb] != s->cursor_end) {

      /* if the cursor position changed, we update the old and new

         chars */

        if (s->cursor_offset < CH_ATTR_SIZE)

            s->last_ch_attr[s->cursor_offset] = -1;

        if (cursor_offset < CH_ATTR_SIZE)

            s->last_ch_attr[cursor_offset] = -1;

        s->cursor_offset = cursor_offset;

        s->cursor_start = s->cr[0xa];

        s->cursor_end = s->cr[0xb];

    }

    cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;



    depth_index = get_depth_index(s->ds);

    if (cw == 16)

        vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];

    else

        vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];

    vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];



    dest = ds_get_data(s->ds);

    linesize = ds_get_linesize(s->ds);

    ch_attr_ptr = s->last_ch_attr;

    for(cy = 0; cy < height; cy++) {

        d1 = dest;

        src = s1;

        cx_min = width;

        cx_max = -1;

        for(cx = 0; cx < width; cx++) {

            ch_attr = *(uint16_t *)src;

            if (full_update || ch_attr != *ch_attr_ptr) {

                if (cx < cx_min)

                    cx_min = cx;

                if (cx > cx_max)

                    cx_max = cx;

                *ch_attr_ptr = ch_attr;

#ifdef WORDS_BIGENDIAN

                ch = ch_attr >> 8;

                cattr = ch_attr & 0xff;

#else

                ch = ch_attr & 0xff;

                cattr = ch_attr >> 8;

#endif

                font_ptr = font_base[(cattr >> 3) & 1];

                font_ptr += 32 * 4 * ch;

                bgcol = palette[cattr >> 4];

                fgcol = palette[cattr & 0x0f];

                if (cw != 9) {

                    vga_draw_glyph8(d1, linesize,

                                    font_ptr, cheight, fgcol, bgcol);

                } else {

                    dup9 = 0;

                    if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))

                        dup9 = 1;

                    vga_draw_glyph9(d1, linesize,

                                    font_ptr, cheight, fgcol, bgcol, dup9);

                }

                if (src == cursor_ptr &&

                    !(s->cr[0x0a] & 0x20)) {

                    int line_start, line_last, h;

                    /* draw the cursor */

                    line_start = s->cr[0x0a] & 0x1f;

                    line_last = s->cr[0x0b] & 0x1f;

                    /* XXX: check that */

                    if (line_last > cheight - 1)

                        line_last = cheight - 1;

                    if (line_last >= line_start && line_start < cheight) {

                        h = line_last - line_start + 1;

                        d = d1 + linesize * line_start;

                        if (cw != 9) {

                            vga_draw_glyph8(d, linesize,

                                            cursor_glyph, h, fgcol, bgcol);

                        } else {

                            vga_draw_glyph9(d, linesize,

                                            cursor_glyph, h, fgcol, bgcol, 1);

                        }

                    }

                }

            }

            d1 += x_incr;

            src += 4;

            ch_attr_ptr++;

        }

        if (cx_max != -1) {

            dpy_update(s->ds, cx_min * cw, cy * cheight,

                       (cx_max - cx_min + 1) * cw, cheight);

        }

        dest += linesize * cheight;

        s1 += line_offset;

    }

}
