qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

cursor.c (6934B)


      1 #include "qemu/osdep.h"
      2 #include "ui/console.h"
      3 
      4 #include "cursor_hidden.xpm"
      5 #include "cursor_left_ptr.xpm"
      6 
      7 /* for creating built-in cursors */
      8 static QEMUCursor *cursor_parse_xpm(const char *xpm[])
      9 {
     10     QEMUCursor *c;
     11     uint32_t ctab[128];
     12     unsigned int width, height, colors, chars;
     13     unsigned int line = 0, i, r, g, b, x, y, pixel;
     14     char name[16];
     15     uint8_t idx;
     16 
     17     /* parse header line: width, height, #colors, #chars */
     18     if (sscanf(xpm[line], "%u %u %u %u",
     19                &width, &height, &colors, &chars) != 4) {
     20         fprintf(stderr, "%s: header parse error: \"%s\"\n",
     21                 __func__, xpm[line]);
     22         return NULL;
     23     }
     24     if (chars != 1) {
     25         fprintf(stderr, "%s: chars != 1 not supported\n", __func__);
     26         return NULL;
     27     }
     28     line++;
     29 
     30     /* parse color table */
     31     for (i = 0; i < colors; i++, line++) {
     32         if (sscanf(xpm[line], "%c c %15s", &idx, name) == 2) {
     33             if (sscanf(name, "#%02x%02x%02x", &r, &g, &b) == 3) {
     34                 ctab[idx] = (0xff << 24) | (b << 16) | (g << 8) | r;
     35                 continue;
     36             }
     37             if (strcmp(name, "None") == 0) {
     38                 ctab[idx] = 0x00000000;
     39                 continue;
     40             }
     41         }
     42         fprintf(stderr, "%s: color parse error: \"%s\"\n",
     43                 __func__, xpm[line]);
     44         return NULL;
     45     }
     46 
     47     /* parse pixel data */
     48     c = cursor_alloc(width, height);
     49     assert(c != NULL);
     50 
     51     for (pixel = 0, y = 0; y < height; y++, line++) {
     52         for (x = 0; x < height; x++, pixel++) {
     53             idx = xpm[line][x];
     54             c->data[pixel] = ctab[idx];
     55         }
     56     }
     57     return c;
     58 }
     59 
     60 /* nice for debugging */
     61 void cursor_print_ascii_art(QEMUCursor *c, const char *prefix)
     62 {
     63     uint32_t *data = c->data;
     64     int x,y;
     65 
     66     for (y = 0; y < c->height; y++) {
     67         fprintf(stderr, "%s: %2d: |", prefix, y);
     68         for (x = 0; x < c->width; x++, data++) {
     69             if ((*data & 0xff000000) != 0xff000000) {
     70                 fprintf(stderr, " "); /* transparent */
     71             } else if ((*data & 0x00ffffff) == 0x00ffffff) {
     72                 fprintf(stderr, "."); /* white */
     73             } else if ((*data & 0x00ffffff) == 0x00000000) {
     74                 fprintf(stderr, "X"); /* black */
     75             } else {
     76                 fprintf(stderr, "o"); /* other */
     77             }
     78         }
     79         fprintf(stderr, "|\n");
     80     }
     81 }
     82 
     83 QEMUCursor *cursor_builtin_hidden(void)
     84 {
     85     return cursor_parse_xpm(cursor_hidden_xpm);
     86 }
     87 
     88 QEMUCursor *cursor_builtin_left_ptr(void)
     89 {
     90     return cursor_parse_xpm(cursor_left_ptr_xpm);
     91 }
     92 
     93 QEMUCursor *cursor_alloc(int width, int height)
     94 {
     95     QEMUCursor *c;
     96     size_t datasize = width * height * sizeof(uint32_t);
     97 
     98     if (width > 512 || height > 512) {
     99         return NULL;
    100     }
    101 
    102     c = g_malloc0(sizeof(QEMUCursor) + datasize);
    103     c->width  = width;
    104     c->height = height;
    105     c->refcount = 1;
    106     return c;
    107 }
    108 
    109 void cursor_get(QEMUCursor *c)
    110 {
    111     c->refcount++;
    112 }
    113 
    114 void cursor_put(QEMUCursor *c)
    115 {
    116     if (c == NULL)
    117         return;
    118     c->refcount--;
    119     if (c->refcount)
    120         return;
    121     g_free(c);
    122 }
    123 
    124 int cursor_get_mono_bpl(QEMUCursor *c)
    125 {
    126     return DIV_ROUND_UP(c->width, 8);
    127 }
    128 
    129 void cursor_set_mono(QEMUCursor *c,
    130                      uint32_t foreground, uint32_t background, uint8_t *image,
    131                      int transparent, uint8_t *mask)
    132 {
    133     uint32_t *data = c->data;
    134     uint8_t bit;
    135     int x,y,bpl;
    136     bool expand_bitmap_only = image == mask;
    137     bool has_inverted_colors = false;
    138     const uint32_t inverted = 0x80000000;
    139 
    140     /*
    141      * Converts a monochrome bitmap with XOR mask 'image' and AND mask 'mask':
    142      * https://docs.microsoft.com/en-us/windows-hardware/drivers/display/drawing-monochrome-pointers
    143      */
    144     bpl = cursor_get_mono_bpl(c);
    145     for (y = 0; y < c->height; y++) {
    146         bit = 0x80;
    147         for (x = 0; x < c->width; x++, data++) {
    148             if (transparent && mask[x/8] & bit) {
    149                 if (!expand_bitmap_only && image[x / 8] & bit) {
    150                     *data = inverted;
    151                     has_inverted_colors = true;
    152                 } else {
    153                     *data = 0x00000000;
    154                 }
    155             } else if (!transparent && !(mask[x/8] & bit)) {
    156                 *data = 0x00000000;
    157             } else if (image[x/8] & bit) {
    158                 *data = 0xff000000 | foreground;
    159             } else {
    160                 *data = 0xff000000 | background;
    161             }
    162             bit >>= 1;
    163             if (bit == 0) {
    164                 bit = 0x80;
    165             }
    166         }
    167         mask  += bpl;
    168         image += bpl;
    169     }
    170 
    171     /*
    172      * If there are any pixels with inverted colors, create an outline (fill
    173      * transparent neighbors with the background color) and use the foreground
    174      * color as "inverted" color.
    175      */
    176     if (has_inverted_colors) {
    177         data = c->data;
    178         for (y = 0; y < c->height; y++) {
    179             for (x = 0; x < c->width; x++, data++) {
    180                 if (*data == 0 /* transparent */ &&
    181                         ((x > 0 && data[-1] == inverted) ||
    182                          (x + 1 < c->width && data[1] == inverted) ||
    183                          (y > 0 && data[-c->width] == inverted) ||
    184                          (y + 1 < c->height && data[c->width] == inverted))) {
    185                     *data = 0xff000000 | background;
    186                 }
    187             }
    188         }
    189         data = c->data;
    190         for (x = 0; x < c->width * c->height; x++, data++) {
    191             if (*data == inverted) {
    192                 *data = 0xff000000 | foreground;
    193             }
    194         }
    195     }
    196 }
    197 
    198 void cursor_get_mono_image(QEMUCursor *c, int foreground, uint8_t *image)
    199 {
    200     uint32_t *data = c->data;
    201     uint8_t bit;
    202     int x,y,bpl;
    203 
    204     bpl = cursor_get_mono_bpl(c);
    205     memset(image, 0, bpl * c->height);
    206     for (y = 0; y < c->height; y++) {
    207         bit = 0x80;
    208         for (x = 0; x < c->width; x++, data++) {
    209             if (((*data & 0xff000000) == 0xff000000) &&
    210                 ((*data & 0x00ffffff) == foreground)) {
    211                 image[x/8] |= bit;
    212             }
    213             bit >>= 1;
    214             if (bit == 0) {
    215                 bit = 0x80;
    216             }
    217         }
    218         image += bpl;
    219     }
    220 }
    221 
    222 void cursor_get_mono_mask(QEMUCursor *c, int transparent, uint8_t *mask)
    223 {
    224     uint32_t *data = c->data;
    225     uint8_t bit;
    226     int x,y,bpl;
    227 
    228     bpl = cursor_get_mono_bpl(c);
    229     memset(mask, 0, bpl * c->height);
    230     for (y = 0; y < c->height; y++) {
    231         bit = 0x80;
    232         for (x = 0; x < c->width; x++, data++) {
    233             if ((*data & 0xff000000) != 0xff000000) {
    234                 if (transparent != 0) {
    235                     mask[x/8] |= bit;
    236                 }
    237             } else {
    238                 if (transparent == 0) {
    239                     mask[x/8] |= bit;
    240                 }
    241             }
    242             bit >>= 1;
    243             if (bit == 0) {
    244                 bit = 0x80;
    245             }
    246         }
    247         mask += bpl;
    248     }
    249 }