Home | History | Annotate | Download | only in libvncserver
      1 /*
      2  * hextile.c
      3  *
      4  * Routines to implement Hextile Encoding
      5  */
      6 
      7 /*
      8  *  OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk (at) incompleteness.net>.
      9  *  Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
     10  *  All Rights Reserved.
     11  *
     12  *  This is free software; you can redistribute it and/or modify
     13  *  it under the terms of the GNU General Public License as published by
     14  *  the Free Software Foundation; either version 2 of the License, or
     15  *  (at your option) any later version.
     16  *
     17  *  This software is distributed in the hope that it will be useful,
     18  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     19  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     20  *  GNU General Public License for more details.
     21  *
     22  *  You should have received a copy of the GNU General Public License
     23  *  along with this software; if not, write to the Free Software
     24  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
     25  *  USA.
     26  */
     27 
     28 #include <rfb/rfb.h>
     29 
     30 static rfbBool sendHextiles8(rfbClientPtr cl, int x, int y, int w, int h);
     31 static rfbBool sendHextiles16(rfbClientPtr cl, int x, int y, int w, int h);
     32 static rfbBool sendHextiles32(rfbClientPtr cl, int x, int y, int w, int h);
     33 
     34 
     35 /*
     36  * rfbSendRectEncodingHextile - send a rectangle using hextile encoding.
     37  */
     38 
     39 rfbBool
     40 rfbSendRectEncodingHextile(rfbClientPtr cl,
     41                            int x,
     42                            int y,
     43                            int w,
     44                            int h)
     45 {
     46     rfbFramebufferUpdateRectHeader rect;
     47 
     48     if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
     49         if (!rfbSendUpdateBuf(cl))
     50             return FALSE;
     51     }
     52 
     53     rect.r.x = Swap16IfLE(x);
     54     rect.r.y = Swap16IfLE(y);
     55     rect.r.w = Swap16IfLE(w);
     56     rect.r.h = Swap16IfLE(h);
     57     rect.encoding = Swap32IfLE(rfbEncodingHextile);
     58 
     59     memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
     60            sz_rfbFramebufferUpdateRectHeader);
     61     cl->ublen += sz_rfbFramebufferUpdateRectHeader;
     62 
     63     rfbStatRecordEncodingSent(cl, rfbEncodingHextile,
     64           sz_rfbFramebufferUpdateRectHeader,
     65           sz_rfbFramebufferUpdateRectHeader + w * (cl->format.bitsPerPixel / 8) * h);
     66 
     67     switch (cl->format.bitsPerPixel) {
     68     case 8:
     69         return sendHextiles8(cl, x, y, w, h);
     70     case 16:
     71         return sendHextiles16(cl, x, y, w, h);
     72     case 32:
     73         return sendHextiles32(cl, x, y, w, h);
     74     }
     75 
     76     rfbLog("rfbSendRectEncodingHextile: bpp %d?\n", cl->format.bitsPerPixel);
     77     return FALSE;
     78 }
     79 
     80 
     81 #define PUT_PIXEL8(pix) (cl->updateBuf[cl->ublen++] = (pix))
     82 
     83 #define PUT_PIXEL16(pix) (cl->updateBuf[cl->ublen++] = ((char*)&(pix))[0], \
     84                           cl->updateBuf[cl->ublen++] = ((char*)&(pix))[1])
     85 
     86 #define PUT_PIXEL32(pix) (cl->updateBuf[cl->ublen++] = ((char*)&(pix))[0], \
     87                           cl->updateBuf[cl->ublen++] = ((char*)&(pix))[1], \
     88                           cl->updateBuf[cl->ublen++] = ((char*)&(pix))[2], \
     89                           cl->updateBuf[cl->ublen++] = ((char*)&(pix))[3])
     90 
     91 
     92 #define DEFINE_SEND_HEXTILES(bpp)                                               \
     93                                                                                 \
     94                                                                                 \
     95 static rfbBool subrectEncode##bpp(rfbClientPtr cli, uint##bpp##_t *data,        \
     96 		int w, int h, uint##bpp##_t bg, uint##bpp##_t fg, rfbBool mono);\
     97 static void testColours##bpp(uint##bpp##_t *data, int size, rfbBool *mono,      \
     98                   rfbBool *solid, uint##bpp##_t *bg, uint##bpp##_t *fg);        \
     99                                                                                 \
    100                                                                                 \
    101 /*                                                                              \
    102  * rfbSendHextiles                                                              \
    103  */                                                                             \
    104                                                                                 \
    105 static rfbBool                                                                  \
    106 sendHextiles##bpp(rfbClientPtr cl, int rx, int ry, int rw, int rh) {            \
    107     int x, y, w, h;                                                             \
    108     int startUblen;                                                             \
    109     char *fbptr;                                                                \
    110     uint##bpp##_t bg = 0, fg = 0, newBg, newFg;                                 \
    111     rfbBool mono, solid;                                                        \
    112     rfbBool validBg = FALSE;                                                    \
    113     rfbBool validFg = FALSE;                                                    \
    114     uint##bpp##_t clientPixelData[16*16*(bpp/8)];                               \
    115                                                                                 \
    116     for (y = ry; y < ry+rh; y += 16) {                                          \
    117         for (x = rx; x < rx+rw; x += 16) {                                      \
    118             w = h = 16;                                                         \
    119             if (rx+rw - x < 16)                                                 \
    120                 w = rx+rw - x;                                                  \
    121             if (ry+rh - y < 16)                                                 \
    122                 h = ry+rh - y;                                                  \
    123                                                                                 \
    124             if ((cl->ublen + 1 + (2 + 16 * 16) * (bpp/8)) >                     \
    125                 UPDATE_BUF_SIZE) {                                              \
    126                 if (!rfbSendUpdateBuf(cl))                                      \
    127                     return FALSE;                                               \
    128             }                                                                   \
    129                                                                                 \
    130             fbptr = (cl->scaledScreen->frameBuffer + (cl->scaledScreen->paddedWidthInBytes * y)   \
    131                      + (x * (cl->scaledScreen->bitsPerPixel / 8)));                   \
    132                                                                                 \
    133             (*cl->translateFn)(cl->translateLookupTable, &(cl->screen->serverFormat),      \
    134                                &cl->format, fbptr, (char *)clientPixelData,     \
    135                                cl->scaledScreen->paddedWidthInBytes, w, h);           \
    136                                                                                 \
    137             startUblen = cl->ublen;                                             \
    138             cl->updateBuf[startUblen] = 0;                                      \
    139             cl->ublen++;                                                        \
    140             rfbStatRecordEncodingSentAdd(cl, rfbEncodingHextile, 1);            \
    141                                                                                 \
    142             testColours##bpp(clientPixelData, w * h,                            \
    143                              &mono, &solid, &newBg, &newFg);                    \
    144                                                                                 \
    145             if (!validBg || (newBg != bg)) {                                    \
    146                 validBg = TRUE;                                                 \
    147                 bg = newBg;                                                     \
    148                 cl->updateBuf[startUblen] |= rfbHextileBackgroundSpecified;     \
    149                 PUT_PIXEL##bpp(bg);                                             \
    150             }                                                                   \
    151                                                                                 \
    152             if (solid) {                                                        \
    153                 continue;                                                       \
    154             }                                                                   \
    155                                                                                 \
    156             cl->updateBuf[startUblen] |= rfbHextileAnySubrects;                 \
    157                                                                                 \
    158             if (mono) {                                                         \
    159                 if (!validFg || (newFg != fg)) {                                \
    160                     validFg = TRUE;                                             \
    161                     fg = newFg;                                                 \
    162                     cl->updateBuf[startUblen] |= rfbHextileForegroundSpecified; \
    163                     PUT_PIXEL##bpp(fg);                                         \
    164                 }                                                               \
    165             } else {                                                            \
    166                 validFg = FALSE;                                                \
    167                 cl->updateBuf[startUblen] |= rfbHextileSubrectsColoured;        \
    168             }                                                                   \
    169                                                                                 \
    170             if (!subrectEncode##bpp(cl, clientPixelData, w, h, bg, fg, mono)) { \
    171                 /* encoding was too large, use raw */                           \
    172                 validBg = FALSE;                                                \
    173                 validFg = FALSE;                                                \
    174                 cl->ublen = startUblen;                                         \
    175                 cl->updateBuf[cl->ublen++] = rfbHextileRaw;                     \
    176                 (*cl->translateFn)(cl->translateLookupTable,                    \
    177                                    &(cl->screen->serverFormat), &cl->format, fbptr,        \
    178                                    (char *)clientPixelData,                     \
    179                                    cl->scaledScreen->paddedWidthInBytes, w, h); \
    180                                                                                 \
    181                 memcpy(&cl->updateBuf[cl->ublen], (char *)clientPixelData,      \
    182                        w * h * (bpp/8));                                        \
    183                                                                                 \
    184                 cl->ublen += w * h * (bpp/8);                                   \
    185                 rfbStatRecordEncodingSentAdd(cl, rfbEncodingHextile,            \
    186                              w * h * (bpp/8));                                  \
    187             }                                                                   \
    188         }                                                                       \
    189     }                                                                           \
    190                                                                                 \
    191     return TRUE;                                                                \
    192 }                                                                               \
    193                                                                                 \
    194                                                                                 \
    195 static rfbBool                                                                  \
    196 subrectEncode##bpp(rfbClientPtr cl, uint##bpp##_t *data, int w, int h,          \
    197                    uint##bpp##_t bg, uint##bpp##_t fg, rfbBool mono)            \
    198 {                                                                               \
    199     uint##bpp##_t cl2;                                                          \
    200     int x,y;                                                                    \
    201     int i,j;                                                                    \
    202     int hx=0,hy,vx=0,vy;                                                        \
    203     int hyflag;                                                                 \
    204     uint##bpp##_t *seg;                                                         \
    205     uint##bpp##_t *line;                                                        \
    206     int hw,hh,vw,vh;                                                            \
    207     int thex,they,thew,theh;                                                    \
    208     int numsubs = 0;                                                            \
    209     int newLen;                                                                 \
    210     int nSubrectsUblen;                                                         \
    211                                                                                 \
    212     nSubrectsUblen = cl->ublen;                                                 \
    213     cl->ublen++;                                                                \
    214     rfbStatRecordEncodingSentAdd(cl, rfbEncodingHextile, 1);                    \
    215                                                                                 \
    216     for (y=0; y<h; y++) {                                                       \
    217         line = data+(y*w);                                                      \
    218         for (x=0; x<w; x++) {                                                   \
    219             if (line[x] != bg) {                                                \
    220                 cl2 = line[x];                                                  \
    221                 hy = y-1;                                                       \
    222                 hyflag = 1;                                                     \
    223                 for (j=y; j<h; j++) {                                           \
    224                     seg = data+(j*w);                                           \
    225                     if (seg[x] != cl2) {break;}                                 \
    226                     i = x;                                                      \
    227                     while ((seg[i] == cl2) && (i < w)) i += 1;                  \
    228                     i -= 1;                                                     \
    229                     if (j == y) vx = hx = i;                                    \
    230                     if (i < vx) vx = i;                                         \
    231                     if ((hyflag > 0) && (i >= hx)) {                            \
    232                         hy += 1;                                                \
    233                     } else {                                                    \
    234                         hyflag = 0;                                             \
    235                     }                                                           \
    236                 }                                                               \
    237                 vy = j-1;                                                       \
    238                                                                                 \
    239                 /* We now have two possible subrects: (x,y,hx,hy) and           \
    240                  * (x,y,vx,vy).  We'll choose the bigger of the two.            \
    241                  */                                                             \
    242                 hw = hx-x+1;                                                    \
    243                 hh = hy-y+1;                                                    \
    244                 vw = vx-x+1;                                                    \
    245                 vh = vy-y+1;                                                    \
    246                                                                                 \
    247                 thex = x;                                                       \
    248                 they = y;                                                       \
    249                                                                                 \
    250                 if ((hw*hh) > (vw*vh)) {                                        \
    251                     thew = hw;                                                  \
    252                     theh = hh;                                                  \
    253                 } else {                                                        \
    254                     thew = vw;                                                  \
    255                     theh = vh;                                                  \
    256                 }                                                               \
    257                                                                                 \
    258                 if (mono) {                                                     \
    259                     newLen = cl->ublen - nSubrectsUblen + 2;                    \
    260                 } else {                                                        \
    261                     newLen = cl->ublen - nSubrectsUblen + bpp/8 + 2;            \
    262                 }                                                               \
    263                                                                                 \
    264                 if (newLen > (w * h * (bpp/8)))                                 \
    265                     return FALSE;                                               \
    266                                                                                 \
    267                 numsubs += 1;                                                   \
    268                                                                                 \
    269                 if (!mono) PUT_PIXEL##bpp(cl2);                                 \
    270                                                                                 \
    271                 cl->updateBuf[cl->ublen++] = rfbHextilePackXY(thex,they);       \
    272                 cl->updateBuf[cl->ublen++] = rfbHextilePackWH(thew,theh);       \
    273                 rfbStatRecordEncodingSentAdd(cl, rfbEncodingHextile, 1);        \
    274                                                                                 \
    275                 /*                                                              \
    276                  * Now mark the subrect as done.                                \
    277                  */                                                             \
    278                 for (j=they; j < (they+theh); j++) {                            \
    279                     for (i=thex; i < (thex+thew); i++) {                        \
    280                         data[j*w+i] = bg;                                       \
    281                     }                                                           \
    282                 }                                                               \
    283             }                                                                   \
    284         }                                                                       \
    285     }                                                                           \
    286                                                                                 \
    287     cl->updateBuf[nSubrectsUblen] = numsubs;                                    \
    288                                                                                 \
    289     return TRUE;                                                                \
    290 }                                                                               \
    291                                                                                 \
    292                                                                                 \
    293 /*                                                                              \
    294  * testColours() tests if there are one (solid), two (mono) or more             \
    295  * colours in a tile and gets a reasonable guess at the best background         \
    296  * pixel, and the foreground pixel for mono.                                    \
    297  */                                                                             \
    298                                                                                 \
    299 static void                                                                     \
    300 testColours##bpp(uint##bpp##_t *data, int size, rfbBool *mono, rfbBool *solid,  \
    301                  uint##bpp##_t *bg, uint##bpp##_t *fg) {                        \
    302     uint##bpp##_t colour1 = 0, colour2 = 0;                                     \
    303     int n1 = 0, n2 = 0;                                                         \
    304     *mono = TRUE;                                                               \
    305     *solid = TRUE;                                                              \
    306                                                                                 \
    307     for (; size > 0; size--, data++) {                                          \
    308                                                                                 \
    309         if (n1 == 0)                                                            \
    310             colour1 = *data;                                                    \
    311                                                                                 \
    312         if (*data == colour1) {                                                 \
    313             n1++;                                                               \
    314             continue;                                                           \
    315         }                                                                       \
    316                                                                                 \
    317         if (n2 == 0) {                                                          \
    318             *solid = FALSE;                                                     \
    319             colour2 = *data;                                                    \
    320         }                                                                       \
    321                                                                                 \
    322         if (*data == colour2) {                                                 \
    323             n2++;                                                               \
    324             continue;                                                           \
    325         }                                                                       \
    326                                                                                 \
    327         *mono = FALSE;                                                          \
    328         break;                                                                  \
    329     }                                                                           \
    330                                                                                 \
    331     if (n1 > n2) {                                                              \
    332         *bg = colour1;                                                          \
    333         *fg = colour2;                                                          \
    334     } else {                                                                    \
    335         *bg = colour2;                                                          \
    336         *fg = colour1;                                                          \
    337     }                                                                           \
    338 }
    339 
    340 DEFINE_SEND_HEXTILES(8)
    341 DEFINE_SEND_HEXTILES(16)
    342 DEFINE_SEND_HEXTILES(32)
    343