| /* |
| * 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) |