/* * hextile.c * * Routines to implement Hextile Encoding */ /* * OSXvnc Copyright (C) 2001 Dan McGuirk . * 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 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)