add libvncserver
[presencevnc] / libvnc / libvncserver / hextile.c
diff --git a/libvnc/libvncserver/hextile.c b/libvnc/libvncserver/hextile.c
new file mode 100755 (executable)
index 0000000..52920d8
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ * hextile.c
+ *
+ * Routines to implement Hextile Encoding
+ */
+
+/*
+ *  OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
+ *  Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.  
+ *  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <rfb/rfb.h>
+
+static rfbBool sendHextiles8(rfbClientPtr cl, int x, int y, int w, int h);
+static rfbBool sendHextiles16(rfbClientPtr cl, int x, int y, int w, int h);
+static rfbBool sendHextiles32(rfbClientPtr cl, int x, int y, int w, int h);
+
+
+/*
+ * rfbSendRectEncodingHextile - send a rectangle using hextile encoding.
+ */
+
+rfbBool
+rfbSendRectEncodingHextile(rfbClientPtr cl,
+                           int x,
+                           int y,
+                           int w,
+                           int h)
+{
+    rfbFramebufferUpdateRectHeader rect;
+    
+    if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
+        if (!rfbSendUpdateBuf(cl))
+            return FALSE;
+    }
+
+    rect.r.x = Swap16IfLE(x);
+    rect.r.y = Swap16IfLE(y);
+    rect.r.w = Swap16IfLE(w);
+    rect.r.h = Swap16IfLE(h);
+    rect.encoding = Swap32IfLE(rfbEncodingHextile);
+
+    memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
+           sz_rfbFramebufferUpdateRectHeader);
+    cl->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    rfbStatRecordEncodingSent(cl, rfbEncodingHextile,
+          sz_rfbFramebufferUpdateRectHeader,
+          sz_rfbFramebufferUpdateRectHeader + w * (cl->format.bitsPerPixel / 8) * h);
+
+    switch (cl->format.bitsPerPixel) {
+    case 8:
+        return sendHextiles8(cl, x, y, w, h);
+    case 16:
+        return sendHextiles16(cl, x, y, w, h);
+    case 32:
+        return sendHextiles32(cl, x, y, w, h);
+    }
+
+    rfbLog("rfbSendRectEncodingHextile: bpp %d?\n", cl->format.bitsPerPixel);
+    return FALSE;
+}
+
+
+#define PUT_PIXEL8(pix) (cl->updateBuf[cl->ublen++] = (pix))
+
+#define PUT_PIXEL16(pix) (cl->updateBuf[cl->ublen++] = ((char*)&(pix))[0], \
+                          cl->updateBuf[cl->ublen++] = ((char*)&(pix))[1])
+
+#define PUT_PIXEL32(pix) (cl->updateBuf[cl->ublen++] = ((char*)&(pix))[0], \
+                          cl->updateBuf[cl->ublen++] = ((char*)&(pix))[1], \
+                          cl->updateBuf[cl->ublen++] = ((char*)&(pix))[2], \
+                          cl->updateBuf[cl->ublen++] = ((char*)&(pix))[3])
+
+
+#define DEFINE_SEND_HEXTILES(bpp)                                               \
+                                                                                \
+                                                                                \
+static rfbBool subrectEncode##bpp(rfbClientPtr cli, uint##bpp##_t *data,        \
+               int w, int h, uint##bpp##_t bg, uint##bpp##_t fg, rfbBool mono);\
+static void testColours##bpp(uint##bpp##_t *data, int size, rfbBool *mono,      \
+                  rfbBool *solid, uint##bpp##_t *bg, uint##bpp##_t *fg);        \
+                                                                                \
+                                                                                \
+/*                                                                              \
+ * rfbSendHextiles                                                              \
+ */                                                                             \
+                                                                                \
+static rfbBool                                                                  \
+sendHextiles##bpp(rfbClientPtr cl, int rx, int ry, int rw, int rh) {            \
+    int x, y, w, h;                                                             \
+    int startUblen;                                                             \
+    char *fbptr;                                                                \
+    uint##bpp##_t bg = 0, fg = 0, newBg, newFg;                                 \
+    rfbBool mono, solid;                                                        \
+    rfbBool validBg = FALSE;                                                    \
+    rfbBool validFg = FALSE;                                                    \
+    uint##bpp##_t clientPixelData[16*16*(bpp/8)];                               \
+                                                                                \
+    for (y = ry; y < ry+rh; y += 16) {                                          \
+        for (x = rx; x < rx+rw; x += 16) {                                      \
+            w = h = 16;                                                         \
+            if (rx+rw - x < 16)                                                 \
+                w = rx+rw - x;                                                  \
+            if (ry+rh - y < 16)                                                 \
+                h = ry+rh - y;                                                  \
+                                                                                \
+            if ((cl->ublen + 1 + (2 + 16 * 16) * (bpp/8)) >                     \
+                UPDATE_BUF_SIZE) {                                              \
+                if (!rfbSendUpdateBuf(cl))                                      \
+                    return FALSE;                                               \
+            }                                                                   \
+                                                                                \
+            fbptr = (cl->scaledScreen->frameBuffer + (cl->scaledScreen->paddedWidthInBytes * y)   \
+                     + (x * (cl->scaledScreen->bitsPerPixel / 8)));                   \
+                                                                                \
+            (*cl->translateFn)(cl->translateLookupTable, &(cl->screen->serverFormat),      \
+                               &cl->format, fbptr, (char *)clientPixelData,     \
+                               cl->scaledScreen->paddedWidthInBytes, w, h);           \
+                                                                                \
+            startUblen = cl->ublen;                                             \
+            cl->updateBuf[startUblen] = 0;                                      \
+            cl->ublen++;                                                        \
+            rfbStatRecordEncodingSentAdd(cl, rfbEncodingHextile, 1);            \
+                                                                                \
+            testColours##bpp(clientPixelData, w * h,                            \
+                             &mono, &solid, &newBg, &newFg);                    \
+                                                                                \
+            if (!validBg || (newBg != bg)) {                                    \
+                validBg = TRUE;                                                 \
+                bg = newBg;                                                     \
+                cl->updateBuf[startUblen] |= rfbHextileBackgroundSpecified;     \
+                PUT_PIXEL##bpp(bg);                                             \
+            }                                                                   \
+                                                                                \
+            if (solid) {                                                        \
+                continue;                                                       \
+            }                                                                   \
+                                                                                \
+            cl->updateBuf[startUblen] |= rfbHextileAnySubrects;                 \
+                                                                                \
+            if (mono) {                                                         \
+                if (!validFg || (newFg != fg)) {                                \
+                    validFg = TRUE;                                             \
+                    fg = newFg;                                                 \
+                    cl->updateBuf[startUblen] |= rfbHextileForegroundSpecified; \
+                    PUT_PIXEL##bpp(fg);                                         \
+                }                                                               \
+            } else {                                                            \
+                validFg = FALSE;                                                \
+                cl->updateBuf[startUblen] |= rfbHextileSubrectsColoured;        \
+            }                                                                   \
+                                                                                \
+            if (!subrectEncode##bpp(cl, clientPixelData, w, h, bg, fg, mono)) { \
+                /* encoding was too large, use raw */                           \
+                validBg = FALSE;                                                \
+                validFg = FALSE;                                                \
+                cl->ublen = startUblen;                                         \
+                cl->updateBuf[cl->ublen++] = rfbHextileRaw;                     \
+                (*cl->translateFn)(cl->translateLookupTable,                    \
+                                   &(cl->screen->serverFormat), &cl->format, fbptr,        \
+                                   (char *)clientPixelData,                     \
+                                   cl->scaledScreen->paddedWidthInBytes, w, h); \
+                                                                                \
+                memcpy(&cl->updateBuf[cl->ublen], (char *)clientPixelData,      \
+                       w * h * (bpp/8));                                        \
+                                                                                \
+                cl->ublen += w * h * (bpp/8);                                   \
+                rfbStatRecordEncodingSentAdd(cl, rfbEncodingHextile,            \
+                             w * h * (bpp/8));                                  \
+            }                                                                   \
+        }                                                                       \
+    }                                                                           \
+                                                                                \
+    return TRUE;                                                                \
+}                                                                               \
+                                                                                \
+                                                                                \
+static rfbBool                                                                  \
+subrectEncode##bpp(rfbClientPtr cl, uint##bpp##_t *data, int w, int h,          \
+                   uint##bpp##_t bg, uint##bpp##_t fg, rfbBool mono)            \
+{                                                                               \
+    uint##bpp##_t cl2;                                                          \
+    int x,y;                                                                    \
+    int i,j;                                                                    \
+    int hx=0,hy,vx=0,vy;                                                        \
+    int hyflag;                                                                 \
+    uint##bpp##_t *seg;                                                         \
+    uint##bpp##_t *line;                                                        \
+    int hw,hh,vw,vh;                                                            \
+    int thex,they,thew,theh;                                                    \
+    int numsubs = 0;                                                            \
+    int newLen;                                                                 \
+    int nSubrectsUblen;                                                         \
+                                                                                \
+    nSubrectsUblen = cl->ublen;                                                 \
+    cl->ublen++;                                                                \
+    rfbStatRecordEncodingSentAdd(cl, rfbEncodingHextile, 1);                    \
+                                                                                \
+    for (y=0; y<h; y++) {                                                       \
+        line = data+(y*w);                                                      \
+        for (x=0; x<w; x++) {                                                   \
+            if (line[x] != bg) {                                                \
+                cl2 = line[x];                                                  \
+                hy = y-1;                                                       \
+                hyflag = 1;                                                     \
+                for (j=y; j<h; j++) {                                           \
+                    seg = data+(j*w);                                           \
+                    if (seg[x] != cl2) {break;}                                 \
+                    i = x;                                                      \
+                    while ((seg[i] == cl2) && (i < w)) i += 1;                  \
+                    i -= 1;                                                     \
+                    if (j == y) vx = hx = i;                                    \
+                    if (i < vx) vx = i;                                         \
+                    if ((hyflag > 0) && (i >= hx)) {                            \
+                        hy += 1;                                                \
+                    } else {                                                    \
+                        hyflag = 0;                                             \
+                    }                                                           \
+                }                                                               \
+                vy = j-1;                                                       \
+                                                                                \
+                /* We now have two possible subrects: (x,y,hx,hy) and           \
+                 * (x,y,vx,vy).  We'll choose the bigger of the two.            \
+                 */                                                             \
+                hw = hx-x+1;                                                    \
+                hh = hy-y+1;                                                    \
+                vw = vx-x+1;                                                    \
+                vh = vy-y+1;                                                    \
+                                                                                \
+                thex = x;                                                       \
+                they = y;                                                       \
+                                                                                \
+                if ((hw*hh) > (vw*vh)) {                                        \
+                    thew = hw;                                                  \
+                    theh = hh;                                                  \
+                } else {                                                        \
+                    thew = vw;                                                  \
+                    theh = vh;                                                  \
+                }                                                               \
+                                                                                \
+                if (mono) {                                                     \
+                    newLen = cl->ublen - nSubrectsUblen + 2;                    \
+                } else {                                                        \
+                    newLen = cl->ublen - nSubrectsUblen + bpp/8 + 2;            \
+                }                                                               \
+                                                                                \
+                if (newLen > (w * h * (bpp/8)))                                 \
+                    return FALSE;                                               \
+                                                                                \
+                numsubs += 1;                                                   \
+                                                                                \
+                if (!mono) PUT_PIXEL##bpp(cl2);                                 \
+                                                                                \
+                cl->updateBuf[cl->ublen++] = rfbHextilePackXY(thex,they);       \
+                cl->updateBuf[cl->ublen++] = rfbHextilePackWH(thew,theh);       \
+                rfbStatRecordEncodingSentAdd(cl, rfbEncodingHextile, 1);        \
+                                                                                \
+                /*                                                              \
+                 * Now mark the subrect as done.                                \
+                 */                                                             \
+                for (j=they; j < (they+theh); j++) {                            \
+                    for (i=thex; i < (thex+thew); i++) {                        \
+                        data[j*w+i] = bg;                                       \
+                    }                                                           \
+                }                                                               \
+            }                                                                   \
+        }                                                                       \
+    }                                                                           \
+                                                                                \
+    cl->updateBuf[nSubrectsUblen] = numsubs;                                    \
+                                                                                \
+    return TRUE;                                                                \
+}                                                                               \
+                                                                                \
+                                                                                \
+/*                                                                              \
+ * testColours() tests if there are one (solid), two (mono) or more             \
+ * colours in a tile and gets a reasonable guess at the best background         \
+ * pixel, and the foreground pixel for mono.                                    \
+ */                                                                             \
+                                                                                \
+static void                                                                     \
+testColours##bpp(uint##bpp##_t *data, int size, rfbBool *mono, rfbBool *solid,  \
+                 uint##bpp##_t *bg, uint##bpp##_t *fg) {                        \
+    uint##bpp##_t colour1 = 0, colour2 = 0;                                     \
+    int n1 = 0, n2 = 0;                                                         \
+    *mono = TRUE;                                                               \
+    *solid = TRUE;                                                              \
+                                                                                \
+    for (; size > 0; size--, data++) {                                          \
+                                                                                \
+        if (n1 == 0)                                                            \
+            colour1 = *data;                                                    \
+                                                                                \
+        if (*data == colour1) {                                                 \
+            n1++;                                                               \
+            continue;                                                           \
+        }                                                                       \
+                                                                                \
+        if (n2 == 0) {                                                          \
+            *solid = FALSE;                                                     \
+            colour2 = *data;                                                    \
+        }                                                                       \
+                                                                                \
+        if (*data == colour2) {                                                 \
+            n2++;                                                               \
+            continue;                                                           \
+        }                                                                       \
+                                                                                \
+        *mono = FALSE;                                                          \
+        break;                                                                  \
+    }                                                                           \
+                                                                                \
+    if (n1 > n2) {                                                              \
+        *bg = colour1;                                                          \
+        *fg = colour2;                                                          \
+    } else {                                                                    \
+        *bg = colour2;                                                          \
+        *fg = colour1;                                                          \
+    }                                                                           \
+}
+
+DEFINE_SEND_HEXTILES(8)
+DEFINE_SEND_HEXTILES(16)
+DEFINE_SEND_HEXTILES(32)